在Parallel.Foreach方法中调用异步方法的问题

时间:2017-02-17 11:53:28

标签: c# .net async-await

我有案例我想在paralle.Foreach循环中调用一个asyn方法

    public void ItemCheck<T>(IList<T> items,int id)
          {       
              Parallel.ForEach(items, (current) =>
            {
                PostData(current,id);
            });
            Console.log("ItemCheck executed")
     }
     public async void PostData<T>(T obj, int id)
      {
        Console.lgo("PosstData executed")
      }

输出:

ItemCheck executed 
PosstData executed

为什么会这样? 在完成PostData 方法的执行之前,执行下一行。如何解决此问题。任何人都可以帮助

2 个答案:

答案 0 :(得分:3)

  

为什么会这样?

因为您使用的是async void

另外 - 正如Jon Skeet所说 - 在这里做并行是没有意义的。并行处理是将工作分成多个线程。你真正想要的是并发,而不是 parallelism ,这可以用Task.WhenAll完成:

public async Task ItemCheckAsync<T>(IList<T> items, int id)
{
  var tasks = items.Select(current => PostDataAsync(current, id));
  await Task.WhenAll(tasks);
}
public async Task PostDataAsync<T>(T obj, int id)

短语“并行”通常用于表示“一次执行多项操作”,但该用法误导您使用Parallel,在这种情况下,这不是合适的工具。这就是为什么我强烈喜欢术语“并发”的一个原因,并为Parallel类所做的事情保留术语“并行”。

答案 1 :(得分:0)

问题是你的PostData方法是异步执行的,没有任何东西告诉并行循环要等到所有任务完成。 我将使用另一种方法来同步执行流程:

var tasks = items
.AsParallel()
.WithDegreeOfParallelisum(...)
.Select(async item => await PostData(item, id))
.ToArray();

Task.WaitAll(tasks);  // this will wait for all tasks to finnish

也是你的异步方法,即使是空的,它们应该返回Task而不是无效。更明确地了解您的代码是这种方法的一个优点,此外,您可以将任务用于任何其他操作,例如等待完成的情况。

 public async Task PostData<T>(T obj, int id)

您是否需要并行创建/启动异步任务然后等待它们?这样做的结果就是并行创建任务(这不是一个繁重的操作,为什么要并行执行?)。 如果除了PostData方法之外你没有在并行循环中做任何额外繁重的工作,我认为你根本不需要并行循环。