Kestrel 是否使用单线程来处理像 Node.js 这样的请求? [英] Is Kestrel using a single thread for processing requests like Node.js?

查看:33
本文介绍了Kestrel 是否使用单线程来处理像 Node.js 这样的请求?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Node.js 事件循环

 ┌─────────────────────────┐┌─>│计时器││ └────────────┬────────────┘│ ┌────────────┴────────────┐│ │ I/O 回调 ││ └────────────┬────────────┘│ ┌────────────┴────────────┐│ │ 闲置,准备││ └────────────┬──────────────┘ ┌──────────────────┐│ ┌────────────┴────────────┐ │ 传入:││ │ 投票│<─────┤ 连接, ││ └────────────┬──────────────┘ │ 数据等││ ┌──────────┴──────────────┐ └──────────────────┘│ │ 检查││ └────────────┬────────────┘│ ┌────────────┴────────────┐└──┤ 关闭回调│└──────────────────────────┘

解决方案

针对 ASP.Net Core 2.0 进行了更新.正如 poke 所指出的,服务器已经在托管和传输之间进行了拆分,其中 libuv 属于传输层.libuv ThreadCount 已移至其自己的 LibuvTransportOptions,它们在您的 Web 主机构建器中使用 UseLibuv() ext 方法单独设置:

  • 如果您检查 LibuvTransportOptions 类在github中,你会看到一个ThreadCount选项:

    ////<摘要>///用于处理请求的 libuv I/O 线程数.///</总结>///<备注>///默认为 <see cref="Environment.ProcessorCount"/> 的一半向下舍入并限制在 1 和 16 之间.///</备注>公共 int ThreadCount { 获取;放;} = ProcessorThreadCount;

  • 该选项可以在您的 Web 主机构建器中对 UseLibuv 的调用中设置.例如:

    public static IWebHost BuildWebHost(string[] args) =>WebHost.CreateDefaultBuilder(args).UseLibuv(opts => opts.ThreadCount = 4).UseStartup<启动>().建造();

在 ASP.NET Core 1.X 中,Libuv 配置是 kestrel 服务器的一部分:

  • 如果您检查 KestrelServerOptions 类在其 github 存储库中,您将看到有一个 ThreadCount 选项:

    ////<摘要>///用于处理请求的 libuv I/O 线程数.///</总结>///<备注>///默认为 <see cref="Environment.ProcessorCount"/> 的一半向下舍入并限制在 1 和 16 之间.///</备注>公共 int ThreadCount { 获取;放;} = 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<启动>().建造();主机.运行();}

挖掘源代码:

  • 您可以看到 libuv 侦听器线程(或 KestrelThreads) 在 KestrelEngine
  • 有些地方会调用ThreadPool 方法,因此它们可以在 CLR 线程池而不是 libuv 线程中运行代码.(使用 ThreadPool.QueueUserWorkItem).该池似乎默认为 最大 32K 线程,可以是修改了通过配置.
  • Frame 委托实际应用程序(如 ASP.Net Core 应用程序)处理请求.

所以我们可以说它为 IO 使用了多个 libuv 事件循环.实际工作是通过标准工作线程在托管代码上完成的,使用 CLR 线程池.

我很想找到更多关于此的权威文档(官方文档没有提供太多细节).我发现的最好的一个是 Damian Edwards 在 第 9 频道.大约在 12 分钟时,他解释说:

  • libuv 使用单线程事件循环模型
  • Kestrel 支持多个事件循环
  • Kestrel 只对 libuv 事件循环进行 IO 工作
  • 所有非 IO 工作(包括与 HTTP 相关的任何工作,如解析、帧等)都是在标准 .net 工作线程上的托管代码中完成的.

此外,快速搜索返回:

Both Kestrel and Node.js are based on libuv.

While Node.js exactly states that it uses an event loop, I can't seem to find if such is the case for Kestrel, or if it utilizes thread pooling / request queue like IIS?

Kestrel behind a web server

Node.js event loop

    ┌───────────────────────┐
 ┌─>│        timers         │
 │  └──────────┬────────────┘
 │  ┌──────────┴────────────┐
 │  │     I/O callbacks     │
 │  └──────────┬────────────┘
 │  ┌──────────┴────────────┐
 │  │     idle, prepare     │
 │  └──────────┬────────────┘      ┌───────────────┐
 │  ┌──────────┴────────────┐      │   incoming:   │
 │  │         poll          │<─────┤  connections, │
 │  └──────────┬────────────┘      │   data, etc.  │
 │  ┌──────────┴────────────┐      └───────────────┘
 │  │        check          │
 │  └──────────┬────────────┘
 │  ┌──────────┴────────────┐
 └──┤    close callbacks    │
    └───────────────────────┘

解决方案

Updated for ASP.Net Core 2.0. As pointed by poke, the server has been split between hosting and transport, where libuv belongs to the transport layer. The libuv ThreadCount has been moved to its own LibuvTransportOptions and they are set separately in your web host builder with the UseLibuv() ext method:

  • If you check the LibuvTransportOptions class in github, you will see a ThreadCount option:

    /// <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;
    

  • The option can be set in the call to UseLibuv, in your web host builder. For example:

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseLibuv(opts => opts.ThreadCount = 4)
            .UseStartup<Startup>()                
            .Build();
    

While in ASP.NET Core 1.X, Libuv config was part of the kestrel server:

  • If you check the KestrelServerOptions class in its github repo, you will see there is a ThreadCount option:

    /// <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;
    

  • The option can be set in the call to UseKestrel, for example in a new ASP.Net Core app:

    public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel(opts => opts.ThreadCount = 4)
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup<Startup>()
            .Build();
    
        host.Run();
    }
    

Digging through the source code:

  • You can see the libuv listener threads (or KestrelThreads) being created in the KestrelEngine
  • Some places will call the 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.
  • The Frame<TContext> delegates to the actual application (like an ASP.Net Core application) for handling the request.

So we could say it uses multiple libuv eventloops for IO. The actual work is done on managed code with standard worker threads, using the CLR thread pool.

I would love to find more authoritative documentation about this (The official docs don't give much detail). The best one I have found is Damian Edwards talking about Kestrel on channel 9. Around minute 12 he explains:

  • libuv uses a single threaded event loop model
  • Kestrel supports multiple event loops
  • Kestrel does only IO work on the libuv event loops
  • All non IO work (including anything related with HTTP like parsing, framing, etc) is done in managed code on standard .net worker threads.

Additionally, a quick search has returned:

  • David Fowler talking about thread pooling in Kestrel here. It also confirms that a request might still jump between threads in ASP.Net Core. (as it was in previous versions)
  • This blogpost looking at Kestrel when it came out
  • This question about how threads are managed in ASP.Net Core.

这篇关于Kestrel 是否使用单线程来处理像 Node.js 这样的请求?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆