c# - 如何在工作服务器上实现类似IIS的线程池

标签 c# multithreading asynchronous azure threadpool

编辑我意识到我的问题陈述不够清楚,并对其进行了大量编辑。
这是一个开放式问题,请您提前道歉。
简而言之,我想在Azure辅助角色中实现IIS样式的异步请求处理。
这可能非常简单,也可能很难疯狂-我正在寻找指向哪里进行研究的指针。
虽然我的实现将使用Azure worker 和服务总线队列,但一般原则适用于 worker 进程正在监听传入请求然后为它们提供服务的任何方案。
IIS的作用
在IIS中,有一个固定大小的线程池。如果同步处理所有请求,则可以并行处理的最大请求数== maxthreads。但是,如果必须执行缓慢的外部I/O来处理请求,则效率会非常低下,因为您可能会导致服务器处于空闲状态,但所有线程都被 bundle 起来以等待外部I/O完成。
MSDN:

On the Web server, the .NET Framework maintains a pool of threads that are used to service ASP.NET requests. When a request arrives, a thread from the pool is dispatched to process that request. If the request is processed synchronously, the thread that processes the request is blocked while the request is being processed, and that thread cannot service another request.

This might not be a problem, because the thread pool can be made large enough to accommodate many blocked threads. However, the number of threads in the thread pool is limited. In large applications that process multiple simultaneous long-running requests, all available threads might be blocked. This condition is known as thread starvation. When this condition is reached, the Web server queues requests. If the request queue becomes full, the Web server rejects requests with an HTTP 503 status (Server Too Busy).


为了克服此问题,IIS具有一些巧妙的逻辑,使您可以异步处理请求:

When an asynchronous action is invoked, the following steps occur:

  1. The Web server gets a thread from the thread pool (the worker thread) and schedules it to handle an incoming request. This worker thread initiates an asynchronous operation.

  2. The worker thread is returned to the thread pool to service another Web request.

  3. When the asynchronous operation is complete, it notifies ASP.NET.

  4. The Web server gets a worker thread from the thread pool (which might be a different thread from the thread that started the asynchronous operation) to process the remainder of the request, including rendering the response.


这里的重点是,当异步请求返回时,该返回 Action 计划在为初始传入请求提供服务的同一线程池之一上运行。这意味着系统限制了同时进行的工作量,这就是我要复制的内容。
我想做的事
我想创建一个Worker角色,该角色将监听Azure Service Bus队列以及TCP套接字上的传入工作请求。像IIS一样,我要有一个最大的线程池大小,并且要限制 worker 并行执行的实际工作量。如果 worker 正在忙于处理现有请求(无论是新的传入请求还是来自先前的异步调用的回调),那么在释放某些线程之前,我不希望接听任何新的传入请求。
限制我同时启动的作业数量没有问题-这很容易控制;它限制了我实际上同时工作的数量。
假设有一个100个线程的线程池。
  • 我收到100条发送电子邮件的请求,每封电子邮件需要5秒钟才能发送到SMTP服务器。如果我将服务器限制为只能同时处理100个请求,那么在CPU完全空闲的情况下,我的服务器将无法在5秒钟内执行任何其他操作。因此,我真的不介意同时开始发送1,000或10,000封电子邮件,因为99%的“请求处理时间”将花费在等待外部I/O上,并且我的服务器仍然非常安静。
    因此,可以通过不加限制地继续接受传入请求来解决特定情况(或仅限制请求的开始,直到我触发异步调用;一旦调用BeginSend,我将返回并开始服务另一个请求)。
  • 现在,想象一下,我有一种请求类型,该请求去数据库读取一些数据,对其进行大量计算,然后将其写回到数据库。有两个数据库请求应该异步进行,但是90%的请求处理时间将花在我的工作人员身上。因此,如果我遵循上述相同的逻辑,并保持启动异步调用的权限,并且仅让return做任何让线程继续运行所需的操作,那么我将得到一台非常重载的服务器。

  • IIS以某种方式确保在异步调用返回时使用相同的固定大小的线程池。这意味着,如果我触发了许多异步调用,然后它们返回并开始使用我的线程,则在这些返回完成之前,IIS将不会接受新请求。这是完美的,因为它可以确保服务器上合理的负载,尤其是当我有多个负载平衡的服务器以及服务器从中选择工作的队列系统时。
    我有一个偷偷摸摸的怀疑,认为这可能很简单,只是我缺少一些基本的东西。也许这太疯狂了。

    最佳答案

    创建线程池应被视为独立于Windows Azure。由于辅助角色实例实际上是Windows 2008 Server R2(或SP2),因此没有什么真正的不同。您只需要通过OnStart()Run()进行设置即可。

    您要做的一件事是在扩展到更多/更少的工作程序实例时,将队列长度用作确定因素。请注意,服务总线队列不会播发队列长度,而Windows Azure队列(基于存储和服务总线)会播发队列长度。使用Windows Azure队列,您需要同步轮询消息(而服务总线队列具有长轮询操作)。复习Service Bus队列和Windows Azure队列here之间的区别可能是一个好主意。

    关于c# - 如何在工作服务器上实现类似IIS的线程池,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10808083/

    相关文章:

    java - 在监视器上同步

    javascript - 为什么对 IDBObjectStore.get() 的调用会导致混淆行为?

    java - Play - 与 3rd 方 API 的异步通信

    objective-c - ReactiveCocoa 信号,用于在观察身份验证状态时获取数据

    c# - ASMX Web 服务可以使用 Response.BinaryWrite 响应吗?

    c# - 泛型继承如何作用于这种类型?

    c# - 什么是 CLR 类?

    c# - C#中的HMAC SHA256解密字符串

    java - 在子线程中访问 HttpServletRequest 请求

    java - 如何让一个方法在后台持续运行直到程序结束?