当前位置: 首页 > 编程语言 > C#

异步方法不能并行运行分享

时间:2023-04-10 13:19:44 C#

异步方法不能并行运行在下面的代码中,在B方法中,代码为Trace.TraceInformation("B-Started");永远不会被调用。该方法应该并行运行吗?使用System.Collections.Generic;使用系统诊断;使用System.Threading.Tasks;namespaceConsoleApplication1{classProgram{privatestaticasyncTaskA(){for(;;){}}privatestaticasyncTaskB(){Trace.TraceInformation("B-Started");}staticvoidMain(string[]args){vartasks=newList{A(),B()};Task.WaitAll(tasks.ToArray());简短的回答是否定的,当您编写两个异步方法时,它们实际上不会并行运行。添加awaitTask.Yield();到你的第一个方法(例如在循环内)将允许他们这样做,但是有更合理和直接的方法,高度依赖于你真正需要的东西(在单个线程上交错执行?实际上在多个线程上并行执行?).长答案首先,将函数声明为异步不会使它们异步运行。它大大简化了语法-在此处阅读有关此概念的更多信息:有效地使用Async和Await进行异步编程A根本不是异步的,因为它的方法主体中没有单个await。在第一次使用await指令之前,它像常规方法一样同步运行。从那时起,您等待的对象将决定接下来会发生什么,即剩余方法运行的上下文。要强制任务在另一个线程上执行,请使用Task.Run或类似的。在这种情况下,添加awaitTask.Yield()可以解决这个问题,因为当前同步上下文为null,这确实会导致任务调度器(应该是ThreadPoolTask??Scheduler)执行线程池线程上的其余操作-一些环境或者配置可能只有一个,所以事情仍然不会并行运行。总结这个故事的寓意:注意这两个概念之间的区别:async修饰符不是神奇的spawn-a-thread-here标记。它的唯一目的是让编译器知道一个方法可能依赖于一些异步操作(一个复杂的数据处理线程,I/O...),所以它必须建立一个状态机来协调这些异步产生的回调操作。要使A在另一个线程上运行,您可以使用Task.Run调用它,它使用您可以等待的Task对象包装对新线程的调用。请注意,等待方法并不意味着您的代码本身与A的执行并行运行:它将始终等待Task对象,告诉编译器您需要Task对象返回的值。在这种情况下,await-ingTask.Run(A)将有效地让您的程序永远运行,等待A返回,这是永远不会发生的事情(除非计算机出现故障)。请记住,将方法标记为异步但实际上不等待任何操作只会产生编译器警告的效果。如果您正在等待不是真正异步的东西(它会立即在调用线程上返回类似Task.FromResult的东西),这将意味着您的程序运行时速度下降。然而,它非常轻微。不,显示的方法不是“并行的”。为什么B从未被调用-您通过一系列.Add调用构建了任务列表-首先添加A()结果。由于方法A没有任何等待,它将在同一个线程上同步运行。然后B()将被调用。现在A永远不会完成(它处于无限循环中),因此真正的代码甚至无法到达对B的调用。请注意,即使创建成功,代码也永远不会完成WaitAll,因为A仍处于无限循环中。如果您希望方法“并行运行”,则需要在新线程上隐式/显式运行它们(即使用Task.Run或Thread.Start),或者对于I/O绑定调用,让方法使用await来释放线程。以上就是C#学习教程:异步方法不能并行运行。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右边联系管理员删除。如需转载请注明出处: