.net 限制竞争执行的任务(引擎盖下)
考虑一个Microsoft.NET Framework应用程序,该应用程序充分利用async/await功能来生成许多同时(或嵌套)的任务。没有明显的“流程”控制,即任务大部分是独立的,不等待彼此完成,因此所有任务都在竞争执行 决定如何/何时调度或执行任务以及在哪个线程上执行任务的框架组件是什么 有哪些可能的过程会从用户代码影响该机制?.net 限制竞争执行的任务(引擎盖下),.net,async-await,.net,Async Await,考虑一个Microsoft.NET Framework应用程序,该应用程序充分利用async/await功能来生成许多同时(或嵌套)的任务。没有明显的“流程”控制,即任务大部分是独立的,不等待彼此完成,因此所有任务都在竞争执行 决定如何/何时调度或执行任务以及在哪个线程上执行任务的框架组件是什么 有哪些可能的过程会从用户代码影响该机制? 编辑 我有一个很好的句子,指出了我的问题的目的: 每当代码等待一个等待者说它尚未完成的等待者时(即,等待者的IsCompleted返回false),该方法需要
编辑
我有一个很好的句子,指出了我的问题的目的: 每当代码等待一个等待者说它尚未完成的等待者时(即,等待者的IsCompleted返回false),该方法需要挂起 这里描述的时间点比我的问题晚了一步——有些东西已经处理了用户代码,构建了waitiable和waitier,很可能捕获了上下文,并决定了哪个线程将执行(或正在执行)任务。我是在问那个“事” 我确实看到了用户代码如何影响框架所采用的路径,但这些都是程序员的外部“教育”决定。假设我们采取每一种可能的途径,我们可以影响和过度饱和它。。。我们正在重击一些设施,对吗?也许没有一句话的答案。。。如果我在下面@Stephen的回答中看不到这一点,我很抱歉——我感谢你的帮助并继续挖掘 (一些相关的主题似乎在sync/await摘要下更深入,比如线程池、上下文。我要朝这个方向挖掘吗?)
结束编辑 自定义任务调度器是(最佳)(唯一)答案吗 出于这个问题的目的,我不考虑节流的任何外部因素,如资源不足(网络、I/O饱和)或业务原因(人为限制)。或者通过尝试跟踪正在执行的内容等方式来破解用户代码限制 同时(也与父子相关)任务 当一个
async
方法调用另一个方法时,可以将这些任务视为“父/子”关系。然而,从技术上讲,这并不是一个问题
控制调度、线程和执行的框架组件是什么
中以及中介绍了这一点。当异步
方法通过等待
挂起自身时,默认情况下,它将捕获当前的同步上下文
(或者当前的任务调度程序
,如果没有当前的同步上下文
),并使用它来恢复该方法。这是默认行为;任何async
方法都可以通过wait
ingconfigurewait(false)
的结果来选择不在其捕获的上下文上恢复。在绝大多数情况下,这将在线程池上执行方法的延续
你首先要考虑的是在任何地方都可以应用<代码> ConfigureAwait(false)<代码>。如果您始终如一地这样做,那么您的延续在很大程度上是由线程池管理的,线程池可以优化可用资源的使用。手动节流应该没有必要
也就是说,有几种方法可以做到这一点
TaskScheduler
您可以使用TaskScheduler
来控制async
延续的执行(只要它们不使用ConfigureAwait(false)
)。在这个调度级别。然而,正如@svick所指出的,任务调度器只“看到”每个async
方法的单个(同步)部分。因此,这通常不是人们寻求的解决方案
第三方物流数据流
如果您主要感兴趣的是限制粗粒度操作(可以根据需要有多个“子”操作),您可以使用ActionBlock
从以下位置执行此操作:
var block=newactionblock(f=>f(),
新的ExecutionDataflowBlockOptions{MaxDegreeOfParallelism=…;});
block.Post(MyMethodAsync);
...
不同于<代码> TaskStalper-方法,TPL数据流的
如果您的节流需求更复杂,另一种方法是。然后,需要限制的每个
async
方法都将以wait WaitAsync
开始执行,并以Release
完成。通过将这些调用放置在您选择的位置,您可以完全控制限制的范围。taskscheduler
s对于限制async
s几乎毫无用处(除非您只想限制非异步部分)。你能解释一下你想做什么以及为什么你想限制任务
s吗?@svick,我把用户代码看作是产生任务的泵(请求运行它们)。框架中的某些东西正在做出决定:“我将在同一个线程上运行此任务,因为…”,或者“我将生成一个线程,因为…”。如果你看到我思维中的缺陷——这正是我试图克服的——我正在努力学习——少想象,多了解。关于你的编辑:每个async
方法开始同步执行;它只有在第一次点击它的wait
(其中!IsCompleted
)时才会变为异步。因此,要安排方法的第一部分,只需将TaskFactory
与自定义TaskScheduler
一起使用。听起来您真正想要的是一些介绍性的async
材料。我建议你(按顺序)阅读:,the,the,
var block = new ActionBlock<Func<Task>>(f => f(),
new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = ...; });
block.Post(MyMethodAsync);
...