【问题标题】:Infinite loop of async method calls [duplicate]异步方法调用的无限循环[重复]
【发布时间】:2017-03-06 11:15:03
【问题描述】:

我必须处理 Gb 的文件并使用具有异步方法的库将它们发送到网络来执行此类操作。

如果我执行以下操作,我想如果它们需要一段时间才能完成,我会得到一个同时工作的无限线程数:

void ProcessFiles()
{
    string[] files = /*a lot of files */

    foreach(file in files)
    {
        MyAsyncMethod(file)
    }
}

async void MyAsyncMethod(string file)
{
    string conent = File.ReadAllBytes(file);
    await MyLibrary.Async(call)
}

当然应该是运行并发线程数的限制,但是会创建几个线程,性能会变差……应该是创建线程的限制……达到这个限制会发生什么?新线程会在当前线程结束后创建吗?会被忽略吗?程序会抛出异常吗??

如何管理这个“无限”数量的异步调用。我应该将其转换为同步调用(Task.start() + Task.wait())并由我自己的线程池管理吗?

谢谢

【问题讨论】:

  • 您确实应该首先运行代码以实际查看它的作用......然后您应该阅读一些关于 await 作用的教程,因为您误解了它的作用......
  • Tasks 和async/await 的全部意义在于您不必进行线程管理。你不必担心。
  • 您似乎对 async/await 的工作原理有些误解。这应该一次只处理一个文件,没有文件的并行读取,因为await 导致当前循环等待(没有阻塞)直到MyLibrary.Async 在移动到下一个文件之前完成。类似于编写可枚举方法时的yield return 语句。
  • 您的代码,就目前而言,正在按顺序对文件进行操作。一旦“等待”被击中,循环就会停止并控制离开这个方法,直到 MyLibrary.Async () 返回。在这一点上,又发生了一次循环迭代,等等。
  • 我已经编辑了我的代码,更新了我正在尝试做的代码,但我担心可以创建的线程数量,因为我需要发送数千个不同的文件几天

标签: c# multithreading asynchronous async-await


【解决方案1】:

上面的代码将最多使用一个线程,而不是您正在使用的线程。 “等待”会向系统请求任务调度,然后在任务完成后返回循环。如果任务实际上将在同一个线程或另一个线程上运行,那不是您可以指望的。

如果您想并行执行调用,从而利用许多线程(许多 CPU 内核),您应该使用 Parallel.For。请记住,您不应该在不确切知道如何做的情况下混合使用线程和异步。

【讨论】:

  • 您不应将Parallel 库与async / await 混合使用。它们是为不同的目的而设计的
  • @MatiasCicero 同意。这正是我写的。
【解决方案2】:

您不必担心线程,.NET 会为您担心它们。

顺便说一下,你提供的代码是异步的,但是顺序运行的:

foreach(string file in files)
{
    byte[] content = File.ReadAllBytes(file);
    await MyLibrary.AsyncCall(content); //<-- Loop is blocked per this await.
}

如果你想实现并行,你应该考虑使用Task.WhenAll,或者Task.WaitAll

在您的具体情况下,MyLibrary.AsyncCall 似乎没有结果,因此您可以使用Task.WaitAll

Task[] tasks = files.Select(File.ReadAllBytes).Select(c => MyLibrary.AsyncCall(c)).ToArray();
Task.WaitAll(tasks); //<-- Will execute concurrently, and get back when they are all done.

对于“Task.WaitAll 是否为每个Task 创建新线程?”的问题,答案是。 (Does the user of async/await create a new thread?

【讨论】:

  • 为什么投反对票?
  • 您刚刚编写的代码导致了 OP 试图避免的所有问题,而这些问题以前不存在。
  • @Servy 请更具体。 OP 试图避免什么?
  • 请随意阅读问题以找出答案,尽管将来我建议您在之前发布答案,而不是之后.
  • @Servy 我已经阅读了这个问题。据我了解,OP 认为他正在同时发送文件,但担心并行线程的数量。
【解决方案3】:
  1. 如果调用确实需要线程,系统会为您管理一个线程池,而不是产生无穷无尽的线程。

  2. 在许多情况下,there is no thread。异步不是多线程的同义词。多线程是异步执行任务的一种技术,但它不是唯一的方法。

【讨论】:

  • 好的,这意味着我发布的示例代码将有效??如果响应是肯定的,如果我没有在 for 循环中等待它们,我该如何管理并等待所有 MyAsyncMethod() 调用结束。
猜你喜欢
  • 2019-07-05
  • 2014-10-09
  • 2012-09-10
  • 2020-09-09
  • 1970-01-01
  • 2020-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多