【问题标题】:limits on asyc execution对 asyc 执行的限制
【发布时间】:2025-12-22 16:55:12
【问题描述】:

假设我有一个需要异步处理的对象集合。

List<Customer> customers = GetAllCustomers();

customers.ForEach(async (e) => { await e.Process(); });

我假设这些将在不保留当前线程的情况下异步处理。我想知道的是集合中的客户数量是否有限制。如果是 100, 000 怎么办。它会在异步队列中排队吗?

** 我也不确定这是否是正确的方法。我真的不需要等待每个客户处理的结果。我只想无缝地处理所有的客户数据。我不在乎每个过程是否失败,因为它将再次被拾取直到成功。我可以使用任务,但我宁愿不创建导致可能的赛车条件等的线程。**

【问题讨论】:

  • 你知道任务是做什么的吗?
  • 您将async void lambda Action 传递给Parallel.ForEach。您应该知道,执行控制将立即返回到 Parallel.ForEach,只要它在 lambda 内达到 await,然后它本质上就是在 Parallel.ForEach 之外的即发即弃的调用。可能不是您想要的?
  • 只要异步命中每条记录,应该没问题。该方法是自给自足的,如果它失败了,它将被重新拾取处理。
  • @AlexJ,这样Parallel.ForEach 甚至可能第一个e.Process() 完成之前返回。例如,如果您在 ASP.NET 控制器方法中调用 Parallel.ForEach,则 HTTP 响应可能会在任何 e.Process() 异步调用有机会完成之前发送到客户端。我真的想不出任何可以接受的场景。如果这仍然是你想要的行为,你不需要Parallel.ForEach,因为你不做任何CPU密集型的工作。只需使用常规的foreach 即可开始您的即发即弃呼叫。

标签: async-await linq-to-objects c#-5.0


【解决方案1】:

我想知道的是,集合中的客户数量是否有限制。如果它是 100, 000 怎么办。它会在异步队列中排队吗?

没有限制。但是,每次处理开始一次;也就是说,Process 方法(我假设它是异步的,应该称为 ProcessAsync)将为每个项目调用一次,并为每个项目返回一个 Task&lt;T&gt;

如果您确实想(异步)等待所有任务完成,您可以使用Task.WhenAll

await Task.WhenAll(customers.Select(e => e.Process()));

【讨论】:

  • 您提到 Process 方法应该称为 ProcessAsync。你是什​​么意思?这是一种自定义方法。它可能被命名为 ProcessCustomer。
  • @AlexJ The Task-based Asynchronous Patterns (TAP) 表示所有异步方法的名称末尾都应该有 Async。这是为了明确哪些方法是异步的(并且必须是 awaited)。
  • 好的,谢谢你的解释。 ProcessAsyc 方法在定义中是否也需要异步?如,public static async Task ProcessAsync(),或者不需要装饰?
  • 如果你需要在方法中使用await,你应该只使用async关键字。但是任何Task-returning 方法都应该以Async 后缀命名。您可能会发现我的 async intro 很有帮助。
  • 好的,谢谢你的链接。出色的解释工作。我还有一个问题是,如果说我在该集合中有 100 个客户并且每个客户都做同样的事情——在某处上传数据并更新数据库记录,而我正在使用 await Task.WhenAll。假设客户 2 对象上传数据,它等待服务器响应两秒钟,客户 1 是否会在 2 等待时尝试数据库更新(假设它完成了上传)?与集合中的所有其他对象相同 - 虽然有些人在等待,但其他人会继续他们可以做的事情吗?。
【解决方案2】:

Tasks更适合这种类型的负载,你可以设置选项来控制多少线程等等。

 List<Task> tasks = new List<Task>();
 customers.ForEach((e) => { Task task = Task.Run(() =>{ e.Process();  tasks.Add(task);})});

 Task.WaitAll(tasks.ToArray());

【讨论】:

  • 任务不是异步的。 *.com/questions/9519414/…
  • Task.WaitAll(tasks.ToArray());如果我没记错的话,将保留当前线程直到完成。
  • @alexJ,是的,你是对的。 Task.WaitAll() 将在其他任务(线程)完成时阻塞主线程。
  • 同样来自 MSDN - async 和 await 关键字不会导致创建额外的线程。异步方法不需要多线程,因为异步方法不在其自己的线程上运行。该方法在当前同步上下文上运行,并且仅在该方法处于活动状态时才使用线程上的时间。您可以使用 Task.Run 将受 CPU 限制的工作转移到后台线程,但后台线程对等待结果可用的进程没有帮助。在几乎所有情况下,基于异步的异步编程方法都优于现有方法。
最近更新 更多