首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >异步/等待任务和WaitHandle

异步/等待任务和WaitHandle
EN

Stack Overflow用户
提问于 2012-08-24 21:15:53
回答 3查看 14.2K关注 0票数 7

假设我有10N个项目(我需要通过http协议获取它们),在代码中,N个任务开始获取数据,每个任务依次获取10个项目。我将这些项目放在一个ConcurrentQueue<Item>中。然后,以线程不安全的方法逐个处理这些项。

代码语言:javascript
复制
async Task<Item> GetItemAsync()
{
    //fetch one item from the internet
}

async Task DoWork()
{
    var tasks = new List<Task>();
    var items = new ConcurrentQueue<Item>();
    var handles = new List<ManualResetEvent>();

    for i 1 -> N
    {
        var handle = new ManualResetEvent(false);
        handles.Add(handle);

        tasks.Add(Task.Factory.StartNew(async delegate
        {
            for j 1 -> 10
            {
                var item = await GetItemAsync();
                items.Enqueue(item);
            }
            handle.Set();
        });
    }

    //begin to process the items when any handle is set
    WaitHandle.WaitAny(handles);

    while(true)
    {
         if (all handles are set && items collection is empty) //***
           break; 
         //in another word: all tasks are really completed

         while(items.TryDequeue(out item))          
         {
              AThreadUnsafeMethod(item);    //process items one by one
         }
    }
}

我不知道what if条件可以放在标记为***的语句中。我不能在这里使用Task.IsCompleted属性,因为我在任务中使用了await,所以任务很快就完成了。指示任务是否执行到最后的bool[]看起来真的很难看,因为我认为ManualResetEvent可以做同样的工作。有人能给我一个建议吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-08-24 22:26:02

嗯,你可以自己构建它,但我认为使用TPL Dataflow会更容易。

类似于:

代码语言:javascript
复制
static async Task DoWork()
{
  // By default, ActionBlock uses MaxDegreeOfParallelism == 1,
  //  so AThreadUnsafeMethod is not called in parallel.
  var block = new ActionBlock<Item>(AThreadUnsafeMethod);

  // Start off N tasks, each asynchronously acquiring 10 items.
  // Each item is sent to the block as it is received.
  var tasks = Enumerable.Range(0, N).Select(Task.Run(
      async () =>
      {
        for (int i = 0; i != 10; ++i)
          block.Post(await GetItemAsync());
      })).ToArray();

  // Complete the block when all tasks have completed.
  Task.WhenAll(tasks).ContinueWith(_ => { block.Complete(); });

  // Wait for the block to complete.
  await block.Completion;
}
票数 6
EN

Stack Overflow用户

发布于 2012-08-24 21:41:33

您可以在超时为零的情况下执行WaitOne来检查状态。像这样的东西应该是有效的:

代码语言:javascript
复制
if (handles.All(handle => handle.WaitOne(TimeSpan.Zero)) && !items.Any())
    break;

http://msdn.microsoft.com/en-us/library/cc190477.aspx

票数 0
EN

Stack Overflow用户

发布于 2012-08-27 09:32:43

谢谢大家。最后我发现CountDownEvent非常适合这个场景。一般的实现看起来像这样:(供其他人参考)

代码语言:javascript
复制
for i 1 -> N
{
    //start N tasks
    //invoke CountDownEvent.Signal() at the end of each task
}

//see if CountDownEvent.IsSet here
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12110145

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档