如何从一个循环内,不必等待调用异步方法? [英] How to call an async method from within a loop without awaiting?

查看:265
本文介绍了如何从一个循环内,不必等待调用异步方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑这块code的,其中有一些正在工作中的一个做了循环,然后递归调用来处理子项目。我想转换DoSomething的(项目),并GetItems(ID),以异步方法,但如果我在等待着他们这里,for循环是要等待每次迭代移动的,基本上失去了并行处理的好处之前完成。我怎么能改善这个方法的性能?是否有可能使用异步办呢/等待?

 公共无效的DoWork(字符串ID)
        {
                变种项= GetItems(ID); //需要时间                如果(项目== NULL)
                    返回;                Parallel.ForEach(项目,项目= GT;
                {
                    DoSomething的(项目); //需要时间
                    DoWork的(item.subItemId);
                });
        }


解决方案
而不是使用

Parallel.ForEach 遍历所有的项目,您可以创建一个任务序列,然后使用 Task.WhenAll 等待他们全部完成。当你的code还涉及递归它变得稍微复杂一点,你需要结合的DoSomething 的DoWork 成单一的方法我已经恰当地命名为 DOIT

 异步任务的DoWork(字符串ID){
  变种项= GetItems(ID);
  如果(项目== NULL)
    返回;
  VAR任务= items.Select(DOIT);
  等待Task.WhenAll(任务);
}异步任务DOIT(项目项目){
  等待DoSomething的(项目);
  等待的DoWork(item.subItemId);
}

混合 Parallel.ForEach 和异步/等待是一个坏主意。 Parallel.ForEach 将让你的code并行和计算密集型并行的,但是你的算法获得最佳性能运行。但是异步/的await让您的code并发执行和被阻塞在IO操作该实例重用线程。

简体 Parallel.ForEach 将设置尽可能多的线程,你有你的电脑上的CPU内核,然后分区​​你迭代在这些线程执行的项目。因此, Parallel.ForEach 应一次在你调用堆栈的底部在那里它就会散开工作,多个线程,并等待它们完成使用。里面每个线程的递归的方式调用 Parallel.ForEach 仅仅是疯了,根本不会提高性能。

Consider this piece of code, where there is some work being done within a for loop, and then a recursive call to process sub items. I wanted to convert DoSomething(item) and GetItems(id) to async methods, but if I await on them here, the for loop is going to wait for each iteration to finish before moving on, essentially losing the benefit of parallel processing. How could I improve the performance of this method? Is it possible to do it using async/await?

public void DoWork(string id)
        {            
                var items = GetItems(id);  //takes time

                if (items == null)
                    return;

                Parallel.ForEach(items, item =>
                {
                    DoSomething(item); //takes time
                    DoWork(item.subItemId);                    
                });           
        }

解决方案

Instead of using Parallel.ForEach to loop over the items you can create a sequence of tasks and then use Task.WhenAll to wait for them all to complete. As your code also involves recursion it gets slightly more complicated and you need to combine DoSomething and DoWork into a single method which I have aptly named DoIt:

async Task DoWork(String id) {
  var items = GetItems(id);
  if (items == null)
    return;
  var tasks = items.Select(DoIt);
  await Task.WhenAll(tasks);
}

async Task DoIt(Item item) {
  await DoSomething(item);
  await DoWork(item.subItemId);
}

Mixing Parallel.ForEach and async/await is a bad idea. Parallel.ForEach will allow your code to execute in parallel and for compute intensive but parallelizable algorithms you get the best performance. However async/await allows your code to execute concurrently and for instance reuse threads that are blocked on IO operations.

Simplified Parallel.ForEach will setup as many threads as you have CPU cores on your computer and then partition the items you are iterating to be executed across these threads. So Parallel.ForEach should be used once at the bottom of your call stack where it will then fan out the work to multiple threads and wait for them to complete. Calling Parallel.ForEach in a recursive manner inside each of these threads is just crazy and will not improve performance at all.

这篇关于如何从一个循环内,不必等待调用异步方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆