虽然Node.js确切地说它使用了an event loop,但我似乎无法找到Kestrel的情况,或者它是否利用像IIS这样的线程池/请求队列?
┌───────────────────────┐
┌─>│ timers │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ I/O callbacks │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ idle, prepare │
│ └──────────┬────────────┘ ┌───────────────┐
│ ┌──────────┴────────────┐ │ incoming: │
│ │ poll │<─────┤ connections, │
│ └──────────┬────────────┘ │ data, etc. │
│ ┌──────────┴────────────┐ └───────────────┘
│ │ check │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
└──┤ close callbacks │
└───────────────────────┘
针对ASP.Net Core 2.0进行了更新。正如poke所指出的,服务器已经在托管和传输之间分开,其中libuv属于传输层。 libuv ThreadCount
已移至其自己的LibuvTransportOptions
,并使用UseLibuv()
ext方法在您的Web主机构建器中单独设置:
LibuvTransportOptions
类,你会看到一个ThreadCount
选项:
/// <summary>
/// The number of libuv I/O threads used to process requests.
/// </summary>
/// <remarks>
/// Defaults to half of <see cref="Environment.ProcessorCount" /> rounded down and clamped between 1 and 16.
/// </remarks>
public int ThreadCount { get; set; } = ProcessorThreadCount;
UseLibuv
中设置该选项。例如:
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseLibuv(opts => opts.ThreadCount = 4)
.UseStartup<Startup>()
.Build();
在ASP.NET Core 1.X中,Libuv配置是kestrel服务器的一部分:
KestrelServerOptions
类,您将看到有一个ThreadCount
选项:
/// <summary>
/// The number of libuv I/O threads used to process requests.
/// </summary>
/// <remarks>
/// Defaults to half of <see cref="Environment.ProcessorCount" /> rounded down and clamped between 1 and 16.
/// </remarks>
public int ThreadCount { get; set; } = ProcessorThreadCount;
UseKestrel
时设置该选项,例如在新的ASP.Net Core应用程序中:
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel(opts => opts.ThreadCount = 4)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
挖掘源代码:
KestrelThreads
中创建的libuv监听器线程(或KestrelEngine
)ThreadPool
方法,这样他们就可以在CLR线程池而不是libuv线程中运行代码。 (使用ThreadPool.QueueUserWorkItem
)。游泳池似乎是默认的max of 32K threads,可以修改via config。Frame<TContext>
委托实际应用程序(如ASP.Net Core应用程序)处理请求。所以我们可以说它为IO使用了多个libuv eventloops。实际工作是使用CLR线程池在具有标准工作线程的托管代码上完成的。
我很想找到更多关于此的权威文档(official docs没有提供太多细节)。我发现的最好的是Damian Edwards在channel 9上谈论Kestrel。大约12分钟,他解释说:
此外,快速搜索已返回:
线程是特定于传输的。使用Daniel J.G.的答案中所述的libuv传输(默认值为2.0),有许多基于机器上逻辑处理器数量的事件循环,并且可以通过设置选项上的值来覆盖。默认情况下,每个连接都绑定到特定线程,并且所有IO操作都在该线程上进行。用户代码在线程池线程上执行,因为我们不相信用户不会阻止IO线程。当您在这些线程池线程(即HttpResponse.WriteAsync
)上进行IO调用时,kestrel会将该工作编组回到套接字绑定的相应IO线程。典型的请求流程如下所示:
[从网络读取]调度到线程池 - > [http解析],[执行中间件管道]调用写入 - >将用户工作排入IO线程[写入网络]
当然,你总是可以告诉红隼你是专家,永远不会阻止IO线程并在其上运行你的代码。但我不会,除非我知道我在做什么(我不知道:D)。