异步方法是否有自己的线程?

36 浏览
0 Comments

异步方法是否有自己的线程?

我对TPL还不熟悉,我想知道:C# 5.0中新增的异步编程支持(通过新的asyncawait关键字)与线程的创建有什么关系?

具体来说,使用async/await会每次创建一个新的线程吗?如果有许多嵌套使用async/await的方法,那么每个方法都会创建一个新的线程吗?

0
0 Comments

异步方法是否拥有自己的线程?

对于这个问题的出现,主要原因是希望能够在执行多个任务时快速完成任务,同时避免创建过多的线程所带来的性能问题。常见的异步任务包括读取文件、等待来自其他服务器的响应或进行高内存访问的计算。这些任务并不是CPU密集型,也就是说它们不会使用到所有的线程资源。

如果所有这些任务都按顺序执行,那么可能需要等待IO任务完成,这样会导致任务完成的时间较长,同时CPU也处于空闲状态。因此,我们希望能够利用并行处理的方式快速完成多个任务,而不是创建多个线程。

在使用async/await关键字时,编译器会在调用async方法时执行代码分支的切换,一旦遇到await关键字,就会回到之前的async方法,直到所有的异步调用完成并且满足了await的要求。

如果某个异步方法在没有调用异步方法的情况下具有较大的CPU负载,那么系统可能会变得无响应,并且所有剩余的异步方法将无法被调用,直到当前任务完成。

至于"为什么说编译器会在调用异步方法时执行代码分支(无论是否使用了await)",这是因为微软官方文档中指出:"如果被async关键字修饰的方法不包含await表达式或语句,那么该方法将同步执行"。因此,async关键字并不会中断代码的执行流程。最终,这个问题得到了更正。

对于重新编排的过程,如果异步方法是一个数据库调用,当调用发生时,某种机制会等待数据库返回,并在工作线程接手之前重新整理同步上下文。这个"某种机制"并不是另一个工作线程,而是使用操作系统的一系列异步IO API。例如,对于数据库连接,这个机制就是一个TCP连接。而在使用微软提供的异步等待方法时,它们会进行必要的操作。对于其他场景(如社交媒体API和其他常用API),也是通过实现这两个底层操作来实现异步处理的。

0
0 Comments

异步方法是指不会创建额外线程的方法。异步方法不需要多线程,因为异步方法不在自己的线程上运行。该方法在当前同步上下文上运行,并且只在方法活动时使用线程的时间。可以使用Task.Run将CPU密集型工作移动到后台线程,但后台线程对于等待结果可用的进程没有帮助。

不是每个操作都需要线程。典型系统中有许多处理器/控制器,包括磁盘控制器、网络卡控制器、GPU等。它们只需要接收来自处理器的命令。然后它们执行命令并在完成后通知处理器(通过中断或其他机制通知)。在此之前,没有涉及线程。发出命令的线程可以进入睡眠状态或进入线程池以便重用。当命令完成时,程序可以通过睡眠线程或线程池线程继续执行。

如果异步/等待方法是一个CPU绑定方法,那么在处理长时间运行的过程时,async需要新线程,对吗?

"异步方法不在自己的线程上运行 - > 另一个线程"。不,它在同一个线程上运行!与调用它的方法相同的线程。它只是在开始“await”某些内容时返回到调用方法,以避免浪费CPU周期。

CPU周期在这个问题/回答中是无关紧要的。

我认为它使用了与Node.js类似的模式。背后有一个线程池和一个事件循环的概念。

异步的名称意味着IO绑定的工作,例如如果工作是向Amazon发送HTTP请求,则不需要生成一个什么都不做,只是等待的线程。但是,异步/等待功能还允许您使用更清晰的界面来处理涉及线程的CPU绑定工作(通常涉及混乱的回调语法)。据我所了解,最后一部分是ConfigureAwait(false),它指定是否需要将工作绝对同步回启动它的线程(在大多数情况下,我认为不需要),这样的性能更好。

令我困惑的是在这里learn.microsoft.com/en-us/dotnet/api/…中说到由Task对象执行的工作通常在线程池线程上异步执行,而不是在主应用程序线程上同步执行,这对我来说有点意味着有一个被分配的线程。虽然我阅读了Stephen Cleary的博客文章,并且确信没有线程... 🙂 blog.stephencleary.com/2013/11/there-is-no-thread.htm

这个解释非常好。stackoverflow.com/a/59918139/926460

线程在等待GPU、磁盘控制器等设备时存在处理时间轴的间隙。awaited任务以非阻塞的方式利用这些间隙。这些间隙很多,使得您的任务似乎是并发完成的。

0
0 Comments

异步方法是否有自己的线程是一个常见的问题,特别是在使用async/await关键字时。根据MSDN的解释,一个异步方法在遇到第一个await表达式之前是同步运行的,此时方法会被暂停,直到等待的任务完成。与此同时,控制权会返回到方法的调用者。下面是一个示例代码来验证这一点。

代码示例中,我们定义了一个Program类,其中包含了一个Print方法用于打印输出,一个Run方法用于启动程序,以及一个Experiment方法作为异步方法。我们可以看到,在await之前的代码是同步执行的,而await之后的代码是异步执行的。

第一次运行的结果显示,await之后的代码在另一个线程上执行。但是,如果我们将Task.Delay替换为自己的代码(SomethingElse方法),我们会发现线程保持不变。

通过这个实验,我们可以得出结论:async/await代码可能会在另一个线程上执行,但前提是该线程是由其他代码创建的,而不是由async/await创建的。在这个例子中,我认为Task.Delay创建了新的线程,所以可以得出结论async/await并不像Stander所说的那样会创建一个新的线程。

总结一下,async/await代码可能会使用另一个线程,但只有在该线程是由其他代码创建时才会如此。感谢这个示例,它解释了一些混淆的问题,即Async Await通常与TAP(Task Async Pattern)中的任务一起使用。因此,一些人错误地认为Async Await会创建一个新的线程,而不是任务。据我理解,TAP模式提供了一种更清晰地管理多线程功能的方式。

0