将异步方法传递给Parallel.ForEach [英] Passing async method into Parallel.ForEach

查看:355
本文介绍了将异步方法传递给Parallel.ForEach的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读有关Parallel.ForEach这篇文章,其中"Parallel.ForEach与传入异步方法不兼容."

I was reading this post about Parallel.ForEach where it was stated that "Parallel.ForEach is not compatible with passing in a async method."

因此,要检查一下我是否编写了这段代码:

So, to check I write this code:

static async Task Main(string[] args)
{
    var results = new ConcurrentDictionary<string, int>();

    Parallel.ForEach(Enumerable.Range(0, 100), async index =>
    {
        var res = await DoAsyncJob(index);
        results.TryAdd(index.ToString(), res);
    });         

    Console.ReadLine();
}

static async Task<int> DoAsyncJob(int i)
{
    Thread.Sleep(100);
    return await Task.FromResult(i * 10);
}

此代码同时填写results词典.

This code fills in the results dictionary concurrently.

顺便说一句,我创建了一个类型为ConcurrentDictionary<string, int>的字典,因为如果在调试模式下浏览其元素时遇到ConcurrentDictionary<int, int>的情况,我会发现该元素是按键排序的,因此我认为添加了优雅元素.

By the way, I created a dictionary of type ConcurrentDictionary<string, int> because in case I have ConcurrentDictionary<int, int> when I explore its elements in debug mode I see that elements are sorted by the key and I thought that elenents was added consequently.

所以,我想知道我的代码是否有效?如果它与传递异步方法不兼容",为什么它运行良好?

So, I want to know is my code is valid? If it "is not compatible with passing in a async method" why it works well?

推荐答案

此代码仅适用于DoAsyncJob并不是真正的异步方法. async不会使方法异步工作.等待已完成的任务(如Task.FromResult返回的任务)也是同步的. async Task Main不包含任何异步代码,这会导致编译器警告.

This code works only because DoAsyncJob isn't really an asynchronous method. async doesn't make a method work asynchronously. Awaiting a completed task like that returned by Task.FromResult is synchronous too. async Task Main doesn't contain any asynchronous code, which results in a compiler warning.

一个演示Parallel.ForEach如何不适用于异步方法的示例应调用一个真正的异步方法:

An example that demonstrates how Parallel.ForEach doesn't work with asynchronous methods should call a real asynchronous method:

    static async Task Main(string[] args)
    {
        var results = new ConcurrentDictionary<string, int>();

        Parallel.ForEach(Enumerable.Range(0, 100), async index =>
        {
            var res = await DoAsyncJob(index);
            results.TryAdd(index.ToString(), res);
        });  
        Console.WriteLine($"Items in dictionary {results.Count}");
    }

    static async Task<int> DoAsyncJob(int i)
    {
        await Task.Delay(100);
        return i * 10;
    }

结果将是

Items in dictionary 0

Parallel.ForEach 没有接受Func<Task>的重载,它仅接受Action委托.这意味着它无法等待任何异步操作.

Parallel.ForEach has no overload accepting a Func<Task>, it accepts only Action delegates. This means it can't await any asynchronous operations.

async index是因为它隐式地是 async void代表.就Parallel.ForEach而言,它只是一个Action<int>.

async index is accepted because it's implicitly an async void delegate. As far as Parallel.ForEach is concerned, it's just an Action<int>.

结果是Parallel.ForEach触发了100个任务,并且从不等待它们完成.这就是为什么在应用程序终止时字典仍然为空的原因.

The result is that Parallel.ForEach fires off 100 tasks and never waits for them to complete. That's why the dictionary is still empty when the application terminates.

这篇关于将异步方法传递给Parallel.ForEach的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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