C# 如何正确使用Async、Wait和ManualResetEvents来控制无限while循环

C# 如何正确使用Async、Wait和ManualResetEvents来控制无限while循环,c#,multithreading,asynchronous,async-await,manualresetevent,C#,Multithreading,Asynchronous,Async Await,Manualresetevent,所以我在这里要做的是: 如果队列不是空的,则使引擎循环并处理对象 如果队列为空,我调用manualresetevent使线程休眠 当添加项目且循环未激活时,我设置ManualReset事件 为了加快速度,我从列表中选择atmost 5项,并对它们异步执行操作,然后等待它们全部完成 问题: 调用AddToUpdateQueueMethod的新调用后,将立即调用这两个列表上的clear方法 在我的脑海中,当我在等待任务时。WhenAll(任务),所以线程应该等待它的完成,然后再继续,因此列表上的cl

所以我在这里要做的是:

  • 如果队列不是空的,则使引擎循环并处理对象
  • 如果队列为空,我调用manualresetevent使线程休眠
  • 当添加项目且循环未激活时,我设置ManualReset事件
  • 为了加快速度,我从列表中选择atmost 5项,并对它们异步执行操作,然后等待它们全部完成
  • 问题:

  • 调用AddToUpdateQueueMethod的新调用后,将立即调用这两个列表上的clear方法
  • 在我的脑海中,当我在等待任务时。WhenAll(任务),所以线程应该等待它的完成,然后再继续,因此列表上的clear只能在任务之后调用。WhenAll(任务)返回
  • 我在这里遗漏了什么,或者有什么更好的方法来实现这一点

        public async Task ThumbnailUpdaterEngine()
        {
            int count;
            List<Task<bool>> tasks = new List<Task<bool>>();
            List<Content> candidateContents = new List<Content>();
            while (true)
            {
    
                for (int i = 0; i < 5; i++)
                {
                    Content nextContent = GetNextFromInternalQueue();
                    if (nextContent == null)
                        break;
                    else
                        candidateContents.Add(nextContent);
    
                }
    
                foreach (var candidateContent in candidateContents)
                {
                    foreach (var provider in interactionProviders)
                    {
                        if (provider.IsServiceSupported(candidateContent.ServiceType))
                        {
                            Task<bool> task = provider.UpdateThumbnail(candidateContent);
                            tasks.Add(task);
                            break;
                        }
                    }
                }
                var results = await Task.WhenAll(tasks);
                tasks.Clear();
                foreach (var candidateContent in candidateContents)
                {
                    if (candidateContent.ThumbnailLink != null && !candidateContent.ThumbnailLink.Equals(candidateContent.FileIconLink, StringComparison.CurrentCultureIgnoreCase))
                    {
                        Task<bool> task = DownloadAndUpdateThumbnailCache(candidateContent);
                        tasks.Add(task);
                    }
                }
                await Task.WhenAll(tasks);
    
                //Clean up for next time the loop comes in.
                tasks.Clear();
                candidateContents.Clear();
    
                lock (syncObject)
                {
                    count = internalQueue.Count;
                    if (count == 0)
                    {
                        isQueueControllerRunning = false;
                        monitorEvent.Reset();
                    }
                }
                await Task.Run(() => monitorEvent.WaitOne());
    
    
            }
        }
    
        private Content GetNextFromInternalQueue()
        {
            lock (syncObject)
            {
                Content nextContent = null;
                if (internalQueue.Count > 0)
                {
                    nextContent = internalQueue[0];
                    internalQueue.Remove(nextContent);
                }
                return nextContent;
            }
        }
    
        public void AddToUpdateQueue(Content content)
        {
            lock (syncObject)
            {
                internalQueue.Add(content);
                if (!isQueueControllerRunning)
                {
                    isQueueControllerRunning = true;
                    monitorEvent.Set();
                }
            }
        }
    
    public异步任务ThumbnailUpdaterEngine()
    {
    整数计数;
    列表任务=新列表();
    List candidateContents=新列表();
    while(true)
    {
    对于(int i=0;i<5;i++)
    {
    Content-nextContent=GetNextFromInternalQueue();
    if(nextContent==null)
    打破
    其他的
    候选内容。添加(下一个内容);
    }
    foreach(candidateContent中的var candidateContent)
    {
    foreach(interactionProviders中的变量提供程序)
    {
    if(provider.IsServiceSupported(candidateContent.ServiceType))
    {
    Task Task=provider.UpdateThumbnail(candidateContent);
    任务。添加(任务);
    打破
    }
    }
    }
    var结果=等待任务.WhenAll(任务);
    任务。清除();
    foreach(candidateContent中的var candidateContent)
    {
    if(candidateContent.ThumbnailLink!=null&!candidateContent.ThumbnailLink.Equals(candidateContent.FileIconLink,StringComparison.CurrentCultureIgnoreCase))
    {
    任务任务=下载并更新HumbnailCache(候选内容);
    任务。添加(任务);
    }
    }
    等待任务。何时(任务);
    //为下一次循环进入清理。
    任务。清除();
    candidateContents.Clear();
    锁定(同步对象)
    {
    count=internalQueue.count;
    如果(计数=0)
    {
    isQueueControllerRunning=false;
    monitoreport.Reset();
    }
    }
    wait Task.Run(()=>monitorEvent.WaitOne());
    }
    }
    私有内容GetNextFromInternalQueue()
    {
    锁定(同步对象)
    {
    Content nextContent=null;
    如果(internalQueue.Count>0)
    {
    nextContent=internalQueue[0];
    internalQueue.Remove(nextContent);
    }
    返回下一个内容;
    }
    }
    public void AddToUpdateQueue(内容)
    {
    锁定(同步对象)
    {
    添加(内容);
    如果(!isQueueControllerRunning)
    {
    isQueueControllerRunning=true;
    monitorepent.Set();
    }
    }
    }
    
    您只需使用TPL数据流即可。它是TPL之上的一个actor框架,支持
    async
    。将
    ActionBlock
    async
    操作和
    MaxDegreeOfParallelism
    一起使用5:

    var block = new ActionBlock<Content>(
        async content => 
        {
            var tasks = interactionProviders.
                Where(provider => provider.IsServiceSupported(content.ServiceType)).
                Select(provider => provider.UpdateThumbnail(content));
            await Task.WhenAll(tasks);
    
            if (content.ThumbnailLink != null && !content.ThumbnailLink.Equals(
                content.FileIconLink, 
                StringComparison.CurrentCultureIgnoreCase))
            {
                await DownloadAndUpdateThumbnailCache(content);
            }
        }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 5});
    

    使用TPL,您几乎不需要使用
    ManualResetEvent
    和类似
    Task.Run(()=>monitorent.WaitOne())
    ,除非您处理一些遗留代码。看看TPL数据流,它提供了很多用于组织管道处理的功能。您要寻找的是一个,这样就可以处理while循环的内部结构,但是如何使while循环在队列为空时休眠,并且仅在队列有内容时才唤醒。我可以使用wait Task.Sleep(someTimeout),但这不是最佳选择。除了块初始化之外,上面的代码将进入while循环,但是如何控制while循环线程。@Jack_2060您不需要这样做。TPL数据流为您处理所有这些。它有5个任务在内部对您的内容运行委托,当任务完成且队列为空时,任务完成。下次发布到块时,将创建一个新任务,以此类推。
    foreach (var content in GetContent())
    {
        block.Post(content);
    }
    
    block.Complete();
    await block.Completion