ActionBlock<T> vs Task.WhenAll

7

我希望知道执行多个异步方法的推荐方式是什么?

在System.Threading.Tasks.Dataflow中,我们可以指定最大并行度,但对于Task.WhenAll来说,无界限可能是默认值吗?

这样做:

var tasks = new List<Task>();
foreach(var item in items)
{
    tasks.Add(myAsyncMethod(item));
}
await Task.WhenAll(tasks.ToArray());

或者那个:
var action = new ActionBlock<string>(myAsyncMethod, new ExecutionDataflowBlockOptions
        {
            MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded,
            BoundedCapacity = DataflowBlockOptions.Unbounded,
            MaxMessagesPerTask = DataflowBlockOptions.Unbounded
        });
foreach (var item in items) { }
{
     action.Post(item);
}
action.Complete();

await action.Completion;

Parallel.ForEach()? - Dmitry Bychenko
2
并行和异步不太搭配,而且这些方法是异步的(我无法改变它们)。 - fred_
1
你展示的 Task.WhenAll 代码与并行执行任务无关 - 对于例如线程池线程、并行等的任何决策,都在 myAsyncMethod 中发生,它(理论上)返回热的 Task - Damien_The_Unbeliever
仅仅是一个注意事项。BoundedCapacity = DataflowBlockOptions.Unbounded 是默认值。如果你在选项中显式地包含它,那么你就有了一个将来可以配置为更好值的可能性。然后你的程序会开始表现出奇怪的行为,你将花费一天半时间来弄清楚为什么。 - Theodor Zoulias
1
当接收块因缓冲区已满而拒绝接受项目时,“Post”方法会将项目丢弃到地板上。为了避免这种不愉快的情况,最好主动使用“await action.SendAsync(item)”,或者如果您不在异步方法中,则使用“action.SendAsync(item)。Wait()”。SendAsync的开销可以忽略不计。 - Theodor Zoulias
2个回答

6
我想知道执行多个异步方法的推荐方式是什么?
附注:实际上不是并行,而是同时进行。
在System.Threading.Tasks.Dataflow中,我们可以指定最大并行度,但对于Task.WhenAll,默认情况下可能是无限制的吗?
正如某人评论的那样,Task.WhenAll只会加入现有任务;当您的代码到达Task.WhenAll时,所有并发决策都已经做出。
您可以通过使用类似SemaphoreSlim的东西来限制纯异步代码。
使用异步并发直接还是TPL Dataflow取决于周围的代码。如果这个并发操作只是一次异步调用,则异步并发是最好的选择;但如果这个并发操作是您数据的"管道"的一部分,则TPL Dataflow可能更适合。

2

两种方法都是可接受的,选择应该根据您的要求进行,因为您可以看到Dataflow为您提供了很多可配置性,否则您在直接使用Tasks时将不得不手动实现。

请注意,在这两种情况下,任务池将负责排队和运行任务,因此行为应保持不变。

Dataflow擅长将可组合的异步操作链在一起,而使用Tasks可以让您获得更细粒度的控制。


好的,如果只是为了并行而不进行链接,那么没有实际的好处吗? - fred_
如果您不需要链接或可组合性,那么这可能是过度设计了。 - Slugart

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接