Использует ли Kestrel один поток для обработки запросов, например Node.js?
И Kestrel, и Node.js основаны на libuv.
Хотя Node.js точно заявляет, что он использует цикл обработки событий, я не могу найти, так ли это в случае с Kestrel, или он использует пул потоков / очередь запросов, как IIS?
Пустельга за веб-сервером
Цикл событий Node.js
┌───────────────────────┐
┌─>│ timers │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ I/O callbacks │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
│ │ idle, prepare │
│ └──────────┬────────────┘ ┌───────────────┐
│ ┌──────────┴────────────┐ │ incoming: │
│ │ poll │<─────┤ connections, │
│ └──────────┬────────────┘ │ data, etc. │
│ ┌──────────┴────────────┐ └───────────────┘
│ │ check │
│ └──────────┬────────────┘
│ ┌──────────┴────────────┐
└──┤ close callbacks │
└───────────────────────┘
2 ответа
Обновлено для ASP.Net Core 2.0. Как указал poke, сервер был разделен между хостингом и транспортом, где libuv принадлежит транспортному уровню. Либув ThreadCount
был перемещен в свой LibubTransportOptions
и они устанавливаются отдельно в вашем веб-хосте с UseLibuv()
метод ext:
Если вы проверите
LibuvTransportOptions
класс в github, вы увидите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
класс в своем репозитории GitHub, вы увидите, что есть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(); }
Копаем исходный код:
- Вы можете увидеть потоки слушателя libuv (или
KestrelThreads
) создается вKestrelEngine
- Некоторые места будут называть
ThreadPool
методы, чтобы они могли запускать код в пуле потоков CLR вместо потоков libuv. (С помощьюThreadPool.QueueUserWorkItem
). Кажется, что пул по умолчанию имеет максимум 32K потоков, которые можно изменить через config. -
Frame<TContext>
делегирует фактическое приложение (например, приложение ASP.Net Core) для обработки запроса.
Таким образом, мы могли бы сказать, что он использует несколько циклов libuv для IO. Фактическая работа выполняется над управляемым кодом со стандартными рабочими потоками с использованием пула потоков CLR.
Я хотел бы найти более авторитетную документацию об этом ( официальные документы не дают подробностей). Лучшее, что я нашел, - это то, что Дамиан Эдвардс говорит о Кестрел на 9 канале Около 12 минут он объясняет:
- libuv использует модель однопоточного цикла обработки событий
- Kestrel поддерживает несколько циклов событий
- Kestrel выполняет только операции ввода-вывода в циклах libuv
- Вся работа, не связанная с вводом-выводом (включая все, что связано с HTTP, например анализ, кадрирование и т. Д.) Выполняется в управляемом коде в стандартных рабочих потоках.net.
Кроме того, быстрый поиск вернулся:
Threading зависит от транспорта. С транспортом libuv (по умолчанию в 2.0), как указано в ответе Даниэля Дж.Г., есть ряд циклов событий, основанных на количестве логических процессоров на машине, и это можно переопределить, установив значение в опциях. По умолчанию каждое соединение связано с конкретным потоком, и все операции ввода-вывода выполняются в этом потоке. Пользовательский код выполняется в потоках пула потоков, потому что мы не верим, что пользователи не будут блокировать потоки ввода-вывода. Когда вы делаете IO-вызовы в этих потоках пула потоков (т.е. HttpResponse.WriteAsync
), kestrel выполняет работу, направленную на то, чтобы вернуться к соответствующему потоку ввода-вывода, к которому был привязан сокет. Типичный поток запросов выглядит следующим образом:
[чтение из сети] отправка в пул потоков -> [ http parsing ], [выполнить промежуточный программный конвейер] вызов для записи -> поставить пользователя в очередь на поток ввода-вывода [запись в сеть]
Конечно, вы всегда можете сказать kestrel, что вы профессионал и никогда не заблокируете поток ввода-вывода и не запустите на нем свой код. Но я бы не стал, если бы не знал, что я делаю (а я не знаю:D).