Kestrel 是否使用单线程来处理像 Node.js 这样的请求?
Is Kestrel using a single thread for processing requests like Node.js?
两者都Kestrel and Node.js are based on libuv。
虽然 Node.js 确切地说它使用 an event loop,但我似乎无法找到 Kestrel 是否属于这种情况,或者它是否像 IIS 一样利用线程池/请求队列?
Web 服务器后面的 Kestrel
Node.js 事件循环
┌───────────────────────┐
┌─>│ 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 方法单独设置:
如果你勾选github中的LibuvTransportOptions
class,你会看到一个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 服务器的一部分:
如果你在它的 github 仓库中检查 KestrelServerOptions
class,你会看到有一个 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 核心应用程序中:
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel(opts => opts.ThreadCount = 4)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
深入挖掘源代码:
- 您可以看到 libuv 侦听器线程(或
KestrelThreads
) being created in the KestrelEngine
- 有些地方会叫
ThreadPool
methods so they can run code in the CLR Thread Pool instead of the libuv threads. (Using ThreadPool.QueueUserWorkItem
). The pool seems to be defaulted with a max of 32K threads which can be modified via config。
Frame<TContext>
委托给实际应用程序(如 ASP.Net 核心应用程序)来处理请求。
所以我们可以说它为 IO 使用了多个 libuv 事件循环。实际工作是使用 CLR 线程池在具有标准工作线程的托管代码上完成的。
我很想找到关于此的更多权威文档(official docs don't give much detail). The best one I have found is Damian Edwards talking about Kestrel on channel 9。他在第 12 分钟左右解释说:
- libuv 使用单线程事件循环模型
- Kestrel 支持多个事件循环
- Kestrel 仅在 libuv 事件循环上进行 IO 工作
- 所有非 IO 工作(包括与 HTTP 相关的任何事情,如解析、框架等)都是在标准 .net 工作线程上的托管代码中完成的。
此外,快速搜索返回:
线程是特定于传输的。使用 libuv 传输(2.0 中的默认设置),如 的回答中所述,有许多基于机器上逻辑处理器数量的事件循环,并且可以通过设置选项的值来覆盖。默认情况下,每个连接都绑定到一个特定的线程,所有 IO 操作都在该线程上进行。用户代码在线程池线程上执行,因为我们不相信用户不会阻塞 IO 线程。当您对这些线程池线程(即 HttpResponse.WriteAsync
)进行 IO 调用时,kestrel 会将其编组回套接字绑定到的适当 IO 线程。典型的请求流程如下所示:
[从网络读取]分派到线程池 -> [http 解析],[执行中间件管道] 调用写入 -> 将用户工作排队到 IO 线程[写入网络]
当然,您可以随时告诉 kestrel 您是专业人士,绝不会阻塞 IO 线程和 运行 您的代码。但我不会,除非我知道我在做什么(我不知道 :D)。
两者都Kestrel and Node.js are based on libuv。
虽然 Node.js 确切地说它使用 an event loop,但我似乎无法找到 Kestrel 是否属于这种情况,或者它是否像 IIS 一样利用线程池/请求队列?
Web 服务器后面的 Kestrel
Node.js 事件循环
┌───────────────────────┐
┌─>│ 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 方法单独设置:
如果你勾选github中的
LibuvTransportOptions
class,你会看到一个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 服务器的一部分:
如果你在它的 github 仓库中检查
KestrelServerOptions
class,你会看到有一个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 核心应用程序中:public static void Main(string[] args) { var host = new WebHostBuilder() .UseKestrel(opts => opts.ThreadCount = 4) .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup<Startup>() .Build(); host.Run(); }
深入挖掘源代码:
- 您可以看到 libuv 侦听器线程(或
KestrelThreads
) being created in theKestrelEngine
- 有些地方会叫
ThreadPool
methods so they can run code in the CLR Thread Pool instead of the libuv threads. (UsingThreadPool.QueueUserWorkItem
). The pool seems to be defaulted with a max of 32K threads which can be modified via config。 Frame<TContext>
委托给实际应用程序(如 ASP.Net 核心应用程序)来处理请求。
所以我们可以说它为 IO 使用了多个 libuv 事件循环。实际工作是使用 CLR 线程池在具有标准工作线程的托管代码上完成的。
我很想找到关于此的更多权威文档(official docs don't give much detail). The best one I have found is Damian Edwards talking about Kestrel on channel 9。他在第 12 分钟左右解释说:
- libuv 使用单线程事件循环模型
- Kestrel 支持多个事件循环
- Kestrel 仅在 libuv 事件循环上进行 IO 工作
- 所有非 IO 工作(包括与 HTTP 相关的任何事情,如解析、框架等)都是在标准 .net 工作线程上的托管代码中完成的。
此外,快速搜索返回:
线程是特定于传输的。使用 libuv 传输(2.0 中的默认设置),如 HttpResponse.WriteAsync
)进行 IO 调用时,kestrel 会将其编组回套接字绑定到的适当 IO 线程。典型的请求流程如下所示:
[从网络读取]分派到线程池 -> [http 解析],[执行中间件管道] 调用写入 -> 将用户工作排队到 IO 线程[写入网络]
当然,您可以随时告诉 kestrel 您是专业人士,绝不会阻塞 IO 线程和 运行 您的代码。但我不会,除非我知道我在做什么(我不知道 :D)。