自从我开始编写 ASP.NET 应用程序时想要添加线程以来,我可以通过 3 种简单的方法在 ASP.NET 应用程序中实现线程化:
- 使用 System.Threading.ThreadPool。
- 使用自定义委托并调用其
BeginInvoke
方法。
- 借助 System.Threading.Thread 类使用自定义线程。
前两种方法提供了一种为应用程序启动工作线程的快速方法。但不幸的是,它们会损害应用程序的整体性能,因为它们消耗来自 ASP.NET 用来处理 HTTP 请求的同一池中的线程。
然后我想使用一个新的Task或者async/await来编写IHttpAsyncHandler
。您可以找到 Drew Marsh 在这里解释的一个示例:https://stackoverflow.com/a/6389323/261950
猜测是使用 Task 或 async/await 仍然消耗 ASP.NET 线程池中的线程,并且出于明显的原因我不想这样做。
您能否告诉我我是否可以在后台线程上使用任务(异步/等待),就像使用System.Threading.Thread
类而不是从线程池< /强>?
预先感谢您的帮助。
托马斯
Since the very begining of writing ASP.NET applications when I wanted to add a threading there are 3 simple ways I can accomplish threading within my ASP.NET application :
- Using the
System.Threading.ThreadPool
.
- Using a custom delegate and calling its
BeginInvoke
method.
- Using custom threads with the aid of
System.Threading.Thread
class.
The first two methods offer a quick way to fire off worker threads for your application. But unfortunately, they hurt the overall performance of your application since they consume threads from the same pool used by ASP.NET to handle HTTP requests.
Then I wanted to use a new Task or async/await to write IHttpAsyncHandler
. One example you can find is what Drew Marsh explains here : https://stackoverflow.com/a/6389323/261950
My guess is that using Task or async/await still consume the thread from the ASP.NET thread pool and I don't want for the obvious reason.
Could you please tell me if I can use Task (async/await) on the background thread like with System.Threading.Thread
class and not from thread pool ?
Thanks in advance for your help.
Thomas
发布评论
评论(6)
这几天我一直在通过互联网寻找信息。让我总结一下到目前为止我发现的内容:
ASP.NET ThreadPool 事实
正如 Andres 所说:什么时候 async/await 不会消耗额外的 ThreadPool 线程?仅在您使用 BCL 异步方法的情况下。使用 IOCP 线程来执行 IO 绑定操作。
Andres 继续...如果您尝试异步执行一些同步代码或您自己的库代码,该代码可能使用额外的 ThreadPool 线程,除非您明确使用 IOCP ThreadPool 或您自己的 ThreadPool。
但据我所知知道你无法选择是否使用 IOCP 线程,并且正确实现 threadPool 是不值得的。我怀疑是否有人能做得更好,已经存在了。
ASP.NET 使用公共语言运行时 (CLR) 线程池中的线程来处理请求。只要线程池中有可用线程,ASP.NET 就可以毫无问题地分派传入请求。
异步
委托
使用ThreadPool中的线程。什么时候您应该开始考虑实现异步执行?
当您的应用程序执行相对较长的 I/O 操作(数据库查询、Web 服务调用和其他 I/O 操作)
如果您想要执行 I/O 工作,那么您应该使用 I/O 线程(I/O 线程) O 完成端口),具体来说,您应该使用您使用的任何库类都支持异步回调。它们的名称以
Begin
和End
开头。如果处理请求的计算成本很低,那么并行性可能是不必要的开销。
我应该创建新线程吗?
避免创建新线程,就像避免瘟疫一样。
如果您实际上正在排队足够的工作项以阻止 ASP.NET 处理进一步的请求,那么您应该使线程池挨饿!如果您同时运行数百个 CPU 密集型操作,那么当计算机已经过载时,使用另一个工作线程来服务 ASP.NET 请求有什么好处。
TPL 呢?
TPL 可以适应使用流程中的可用资源。如果服务器已经加载,TPL 可以只使用一个工作线程并向前推进。如果服务器大部分是空闲的,它们可以增长到使用线程池可以空闲的尽可能多的工作线程。
任务使用线程池线程来执行。
参考
I've been looking for information through internet for a couple of days. Let me sum up what I found until now :
ASP.NET ThreadPool facts
As Andres said: When async/await will not consume an additional ThreadPool thread ? Only in the case you are using BCL Async methods. that uses an IOCP thread to execute the IO bound operation.
Andres continues with ...If you are trying to async execute some sync code or your own library code, that code will probably use an additional ThreadPool thread unless you explicitely use the IOCP ThreadPool or your own ThreadPool.
But as far as I know you can't chose whetever you want to use a IOCP thread, and making correct implementation of the threadPool is not worth the effort. I doubt someone does a better one that already exists.
ASP.NET uses threads from a common language runtime (CLR) thread pool to process requests. As long as there are threads available in the thread pool, ASP.NET has no trouble dispatching incoming requests.
Async
delegates
use the threads from ThreadPool.When you should start thinking about implementing asynchronous execution ?
When your application performs relatively lengthy I/O operations (database queries, Web service calls, and other I/O operations)
If you want to do I/O work, then you should be using an I/O thread (I/O Completion Port) and specifically you should be using the async callbacks supported by whatever library class you're using. Theirs names start with the words
Begin
andEnd
.If requests are computationally cheap to process, then parallelism is probably an unnecessary overhead.
If the incoming request rate is high, then adding more parallelism will likely yield few benefits and could actually decrease performance, since the incoming rate of work may be high enough to keep the CPUs busy.
Should I create new Threads ?
Avoid creating new threads like you would avoid the plague.
If you are actually queuing enough work items to prevent ASP.NET from processing further requests, then you should be starving the thread pool! If you are running literally hundreds of CPU-intensive operations at the same time, what good would it do to have another worker thread to serve an ASP.NET request, when the machine is already overloaded.
And the TPL ?
TPL can adapt to use available resources within a process. If the server is already loaded, the TPL can use as little as one worker and make forward progress. If the server is mostly free, they can grow to use as many workers as the ThreadPool can spare.
Tasks use threadpool threads to execute.
References
说“0(零)个线程将服务此请求”并不完全准确。
我认为你的意思是“来自 ASP.NET ThreadPool”,在一般情况下这是正确的。
什么时候async/await不会消耗额外的ThreadPool线程?
仅当您使用 BCL 异步方法(如 WebClient 异步扩展提供的方法)时,该方法使用 IOCP 线程来执行 IO 绑定操作。
如果您尝试异步执行某些同步代码或您自己的库代码,则该代码可能会使用额外的 ThreadPool 线程,除非您明确使用 IOCP ThreadPool 或您自己的 ThreadPool。
谢谢,
安德烈斯.
Saying that "0 (zero) threads will be servicing this request" is not accurate entirely.
I think you mean "from the ASP.NET ThreadPool", and in the general case that will be correct.
When async/await will not consume an additional ThreadPool thread?
Only in the case you are using BCL Async methods (like the ones provided by WebClient async extensions) that uses an IOCP thread to execute the IO bound operation.
If you are trying to async execute some sync code or your own library code, that code will probably use an additional ThreadPool thread unless you explicitely use the IOCP ThreadPool or your own ThreadPool.
Thanks,
Andrés.
并行扩展团队有一篇博客文章 using TPL with ASP.NET 解释了 TPL 和 PLINQ 如何使用 ASP.NET ThreadPool。该帖子甚至还有一个决策图来帮助您选择正确的方法。
简而言之,PLINQ 在整个查询执行过程中为每个核心使用线程池中的一个工作线程,如果流量较高,这可能会导致问题。
另一方面,Task 和 Parallel 方法将适应进程的资源,并且可以使用少至一个线程进行处理。
就异步 CTP 而言,async/await 构造和直接使用任务之间几乎没有概念差异。编译器使用一些魔法在幕后将等待转换为任务和延续。最大的区别是您的代码更加清晰并且更易于调试。
The Parallel Extensions team has a blog post on using TPL with ASP.NET that explains how TPL and PLINQ use the ASP.NET ThreadPool. The post even has a decision chart to help you pick the right approach.
In short, PLINQ uses one worker thread per core from the threadpool for the entire execution of the query, which can lead to problems if you have high traffic.
The Task and Parallel methods on the other hand will adapt to the process's resources and can use as little as one thread for processing.
As far as the Async CTP is concerned, there is little conceptual difference between the async/await construct and using Tasks directly. The compiler uses some magic to convert awaits to Tasks and Continuations behind the scenes. The big difference is that your code is much MUCH cleaner and easier to debug.
另一件需要考虑的事情是 async/await 和 TPL(任务)不是同一件事。
请阅读这篇优秀的文章 http://blogs.msdn.com/b/ericlippert/archive/2010/11/04/asynchrony-in-c-5-0-part-four-it-s-not-magic。 aspx 来理解为什么 async/await 并不意味着“使用后台线程”。
回到我们这里的主题,在您想要在 AsyncHandler 中执行一些昂贵的计算的特定情况下,您有三种选择:
1)将代码保留在 Asynchandler 中,以便昂贵的计算将使用 ThreadPool 中的当前线程。
2)使用Task.Run或Delegate在另一个ThreadPool线程中运行昂贵的计算代码
3) 在自定义线程池(或 IOCP 线程池)中的另一个线程中运行昂贵的计算代码。
第二种情况可能对您来说足够了,具体取决于您的“计算”过程运行的时间以及您有多少负载。安全选项是#3,但编码/测试成本要高得多。我还建议始终将 .NET 4 用于使用异步设计的生产系统,因为 .NET 3.5 中存在一些硬性限制。
Another thing to consider is that async/await and TPL (Task) are not the same thing.
Please read this excellent post http://blogs.msdn.com/b/ericlippert/archive/2010/11/04/asynchrony-in-c-5-0-part-four-it-s-not-magic.aspx to understand why async/await doesn't mean "using a background thread".
Going back to our topic here, in your particular case where you want to perform some expensive calculations inside an AsyncHandler you have three choices:
1) leave the code inside the Asynchandler so the expensive calculation will use the current thread from the ThreadPool.
2) run the expensive calculation code in another ThreadPool thread by using Task.Run or a Delegate
3) Run the expensive calculation code in another thread from your custom thread pool (or IOCP threadPool).
The second case MIGHT be enough for you depending on how long your "calculation" process run and how much load you have. The safe option is #3 but a lot more expensive in coding/testing. I also recommend always using .NET 4 for production systems using async design because there are some hard limits in .NET 3.5.
SignalR 项目中的 .NET 4.0 有一个很好的 HttpTaskAsyncHandler 实现。您可能想检查一下:http://bit.ly/Jfy2s9
There's a nice implementation of HttpTaskAsyncHandler for the .NET 4.0 in the SignalR project. You may want to ckeck it out: http://bit.ly/Jfy2s9
这种情况正是
Task
、async
和await
真正发挥作用的地方。这是同一个示例,经过重构以充分利用async
(它还使用了我的 中的一些辅助类AsyncEx 库来清理映射代码):(如代码中所述,.NET 4.5 有一个
HttpTaskAsyncHandler
< /a> 与上面的 HttpAsyncHandlerBase 类似)。async
的真正酷之处在于它在执行后台操作时不占用任何线程:WebClient
下载。await
实际上从async
方法返回,从而离开请求线程。该请求线程将返回到线程池 - 留下 0(零)个线程来服务该请求。async
方法将在请求线程上恢复。该请求线程仅用于编写实际响应。这是最佳的线程解决方案(因为需要请求线程来写入响应)。
原始示例还以最佳方式使用了线程 - 就线程而言,它与基于异步的代码相同。但在我看来,异步代码更容易阅读。
如果您想了解有关
async
的更多信息,我有一个This situation is where
Task
,async
, andawait
really shine. Here's the same example, refactored to take full advantage ofasync
(it also uses some helper classes from my AsyncEx library to clean up the mapping code):(As noted in the code, .NET 4.5 has a
HttpTaskAsyncHandler
which is similar to ourHttpAsyncHandlerBase
above).The really cool thing about
async
is that it doesn't take any threads while doing the background operation:WebClient
.await
actually returns out of theasync
method, leaving the request thread. That request thread is returned back to the thread pool - leaving 0 (zero) threads servicing this request.async
method is resumed on a request thread. That request thread is briefly used just to write the actual response.This is the optimal threading solution (since a request thread is required to write the response).
The original example also uses threads optimally - as far as the threading goes, it's the same as the
async
-based code. But IMO theasync
code is easier to read.If you want to know more about
async
, I have an intro post on my blog.