c# - 将异步方法传递给 Parallel.ForEach

标签 c# async-await parallel.foreach

<分区>

我正在阅读 this post关于Parallel.ForEach其中指出“Parallel.ForEach 与传入异步方法不兼容。”

所以,为了检查我写了这段代码:

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字典并发。

顺便说一下,我创建了一个 ConcurrentDictionary<string, int> 类型的字典因为万一我有 ConcurrentDictionary<int, int>当我在 Debug模式下探索它的元素时,我看到元素是按键排序的,我认为相应地添加了元素。

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

最佳答案

此代码之所以有效,是因为 DoAsyncJob并不是真正的异步方法。 async不会使方法异步工作。等待由 Task.FromResult 返回的已完成任务也是同步的。 async Task Main不包含任何导致编译器警告的异步代码。

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

    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代表们。这意味着它不能等待任何异步操作。

async index被接受是因为它隐式地是一个 async void delegate .至于Parallel.ForEach而言,它只是一个Action<int> .

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

关于c# - 将异步方法传递给 Parallel.ForEach,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53497077/

相关文章:

c# - Silverlight 中位图和图形(在 Windows 窗体中找到)的等价物是什么?

c# - 为什么覆盖 Parallel.foreach 循环的 .NET 单元测试依赖于硬件?

javascript - 这个 JavaScript 示例是否创建 “race conditions” ? (只要它们可以存在于 JavaScript 中)

c# - 获取异步 : not returning HttpResponseMessage

c# - Parallel.ForEach 与 Task.Run 和 Task.WhenAll

c# - 系统.线程.任务.并行

c# - SerialPort.ReadTo() 上的 ArgumentOutOfRangeException

c# - 异步 Web API 端点

c# - 将 Borland C++ 迁移到 C#

c# - 如何在移动设备休眠时继续执行?