简体   繁体   English

如何正确使用Async,Await和ManualResetEvents控制无限的while循环

[英]How to properly use Async, Await and ManualResetEvents to control an infinite while loop

So what i am trying to do here is: 所以我想在这里做的是:

  1. Make the engine loop and work on an object if the queue is not empty. 如果队列不为空,则使引擎循环并在对象上工作。
  2. If the queue is empty i call the manualresetevent to make the thread sleep. 如果队列为空,我调用manualresetevent使线程进入睡眠状态。
  3. When a item is added and the loop is not active i set the manualresetevent. 当添加项目并且循环未激活时,我设置了manualresetevent。
  4. To make it faster i pick up atmost 5 items from the list and perform operation on them asynchronously and wait for all of them to finish. 为了使其更快,我从列表中挑选了最多5个项目,并对它们进行异步操作,并等待所有项目完成。

Problem: 问题:

  1. The clear methods on the two lists are called as soon as a new call to the AddToUpdateQueueMethod is called. 调用AddToUpdateQueueMethod的新调用后,即会立即调用两个列表中的clear方法。
  2. In my head as i am waiting for Task.WhenAll(tasks), so thread should wait for its completion before moving ahead, hence the clear on the lists should only be called on after Task.WhenAll(tasks) returns. 在我的脑海中,我正在等待Task.WhenAll(tasks),因此线程应在继续操作之前等待其完成,因此,仅在Task.WhenAll(tasks)返回之后才应调用列表上的clear。

What am i missing here, or what will be a better way to achieve this. 我在这里缺少什么,或者将是实现此目标的更好方法。

    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();
            }
        }
    }

You should simply use TPL Dataflow. 您应该只使用TPL Dataflow。 It's an actor framework on top of the TPL with an async support. 它是TPL之上的actor框架,具有async支持。 Use an ActionBlock with an async action and MaxDegreeOfParallelism of 5: 使用具有async操作且MaxDegreeOfParallelism为5的ActionBlock

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});

foreach (var content in GetContent())
{
    block.Post(content);
}

block.Complete();
await block.Completion

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM