fre*_*eud 3 .net multithreading asynchronous
我试图理解async/await模式的基本机制,我想在阅读Jennifer Marsman 撰写的.NET 4.0中的杰出工作之后我得到了它 .我的理解是
1 - 线程池有全局队列,线程池中的每个线程都有本地队列
2 - 请求进入,在全局队列中,然后线程池中的thread1(T1)抓取请求.
3 - 此请求是async\await方法.一旦命中了await关键字,就会创建一个包含在任务中的书签(回调)(假定任务未完成),并且此任务被放置在T1的本地队列中.T1返回池中
4 - 任务完成后,如果T1不忙,T1将处理该请求.但是如果T1忙,另一个线程(称之为T2)可能实际上从T1的本地队列中窃取了这个任务
这是我的问题所在.这是如何被禁止的?我读到的所有内容都表明async\await不会改变线程上下文.请参阅链接MSDN对async\await的解释这也是有意义的,因为在MVC应用程序中,请求绑定到一个线程.这意味着如果请求来到异步操作方法,我希望初始和延续任务都由同一个线程池线程完成.工作如何窃取线程不会干扰这一点?欣赏任何洞察力.
这里有三个半独立系统:线程池(带有工作窃取队列),ASP.NET请求上下文和async
/ await
.
线程池按照您的描述工作:每个线程都有自己的队列,但如果需要可以从其他线程的队列中窃取.但这实际上与ASP.NET的工作方式async
/ await
工作方式没什么关系.在大多数情况下,您可以完全忽略工作窃取队列的工作方式,因为逻辑抽象是具有单个队列的单个线程池.窃取队列的工作只是一种优化.
ASP.NET请求上下文管理诸如HttpContext.Current
安全性和文化之类的东西.它不依赖于特定的线程,但一次只允许一个线程在一个上下文中.这种模式适用于旧式异步请求以及新式async
请求.请注意,请求仅针对同步请求从头到尾绑定到线程; 对于异步请求(并且从未如此),情况并非如此.ASP.NET请求上下文实现为同步上下文 - 特别是,实例AspNetSynchronizationContext
.
当您的代码await
不完整时Task
,默认情况下await
将捕获当前上下文(SynchronizationContext.Current
除非它是null
,在这种情况下它是当前上下文TaskScheduler
).当Task
完成,则该async
方法是,上下文中继续.我在我的博客上更详细地描述了这种行为.您可以将async
/ await
视为"线程不可知"; 也就是说,它们不一定在不同的线程上恢复,也不一定在同一个线程上恢复.他们将所有线程决策留给捕获的上下文.
另外一个注意事项是,有两种不同类型的Task
s,Promise Tasks和Delegate Tasks(正如我在我的博客中描述的那样).只有委托任务实际上有代码才能运行,并且根本就排队到线程池.因此,当await
决定暂停其方法时,它没有代码可以运行,并且当时没有任何排队; 相反,它设置了一个回调(延续),将在将来对该方法的其余部分进行排队.
当等待的任务完成时,将运行该回调/继续,该async
方法将方法的其余部分排队到捕获的上下文.理论上,这可以将它排队到线程池,但实际上有一个几乎总是采用的快捷方式:完成任务的线程通常是一个线程池线程本身,所以它只是直接进入请求上下文然后继续执行async
方法,实际上不必在任何地方排队.
因此,在绝大多数情况下,工作窃取队列根本不起作用.它实际上只发生在线程池超负荷工作时.
但请注意,async
在一个线程上启动处理程序并在另一个线程上继续处理是完全可能的(并且很常见).这通常不是问题,因为保留了请求上下文,但线程局部变量之类的线程仿射结构将无法正常工作.
归档时间: |
|
查看次数: |
741 次 |
最近记录: |