C# Parallel.ForEach 和 Task.WhenAll 有时返回的值比假设的要少

标签 c# async-await task parallel-foreach configureawait

我有这个:

Parallel.ForEach(numbers, (number) =>
{
    var value = Regex.Replace(number, @"\s+", "%20");

    tasks.Add(client.GetAsync(url + value));
});

await Task.WhenAll(tasks).ConfigureAwait(false);

foreach (var task in tasks)
{
  ...
}
有时在到达 foreach(任务中的 var 任务)时返回较少的任务,但在几次请求后,开始返回所有任务。
我已将 ConfigureAwait 更改为 true,但有时仍会返回较少的任务。
顺便说一句,我使用 Parallel.ForEach 因为每个 client.GetAsync(url + value) 都是对外部 api 的请求,其特殊性在于其 99% 的请求的延迟 SLA 低于 1s
你们能解释一下为什么它有时会返回较少的任务吗?
有没有办法保证总是返回所有任务?
谢谢

最佳答案

And is there a way to guarantee returning always all tasks?


评论中的几个人指出你应该这样做,假设 numbers是一个非线程安全列表:
    foreach(var number in numbers)
    {
        var value = Regex.Replace(number, @"\s+", "%20");

        tasks.Add(client.GetAsync(url + value));
    }

    await Task.WhenAll(tasks).ConfigureAwait(false);

    foreach (var task in tasks)
    {
      ...
    }
并行创建执行下载的任务似乎没有任何显着的好处;这发生得非常快。等待下载完成是在 WhenAll 中完成的。
ps;有多种更复杂的方法可以为 URL 转义数据,但是如果您特别希望将任何类型的空格转换为 %20,我想用正则表达式来做是有意义的。
编辑;你问什么时候使用 Parallel ForEach,我会说“通常不要,因为你必须更加小心你使用它的上下文”,但是如果你让 Parallel.ForEach 做更多同步工作,这可能是有道理的:
    Parallel.ForEach(numbers, number =>
    {
        var value = Regex.Replace(number, @"\s+", "%20");

        var r = client.Get(url + value));

        //do something meaningful with r here, i.e. whatever ... is in your  foreach (var task in tasks)

    });
但是请注意,如果您出于协调目的从主体内部对某些共享事物执行更新,则它需要是线程安全的

关于C# Parallel.ForEach 和 Task.WhenAll 有时返回的值比假设的要少,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66623556/

相关文章:

c# - 通过二进制文件可以看到源代码吗? (C#)

c# - 内存映射文件 : How much memory can be allocated for files

c# - ASP.NET Web API Client ProgressMessageHandler Post Task 卡在 WinForm App 中

JavaFX 服务/任务/ worker 和自动化

c# - 我应该用 Task.Run 包装慢速调用吗?

c# - 取消阻止 AcceptTcpClient 调用

c# - Asp.net 中的 session 是否在网站用户之间共享?

c# - 如何在 .NET SoapFormatter 中控制命名空间?

c# - 如何将 Task<TDerived> 转换为 Task<TBase>?

javascript - Nodejs 中用于递归获取 promise 的异步生成器