diff --git a/src/Servers/Kestrel/Transport.Sockets/src/Internal/IOQueue.cs b/src/Servers/Kestrel/Transport.Sockets/src/Internal/IOQueue.cs index b378718f1826..0c958b7ce255 100644 --- a/src/Servers/Kestrel/Transport.Sockets/src/Internal/IOQueue.cs +++ b/src/Servers/Kestrel/Transport.Sockets/src/Internal/IOQueue.cs @@ -10,6 +10,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal; internal sealed class IOQueue : PipeScheduler, IThreadPoolWorkItem { + public static readonly int DefaultCount = DetermineDefaultCount(); + private readonly ConcurrentQueue _workItems = new ConcurrentQueue(); private int _doingWork; @@ -73,4 +75,22 @@ public Work(Action callback, object? state) State = state; } } + + private static int DetermineDefaultCount() + { + // Since each IOQueue schedules one work item to process its work, the number of IOQueues determines the maximum + // parallelism of processing work queued to IOQueues. The default number below is based on the processor count and tries + // to use a high-enough number for that to not be a significant limiting factor for throughput. + // + // On Windows, the default number is limited due to some other perf issues. Once those are fixed, the same heuristic + // could apply there as well. + + int processorCount = Environment.ProcessorCount; + if (OperatingSystem.IsWindows() || processorCount <= 32) + { + return Math.Min(processorCount, 16); + } + + return processorCount / 2; + } } diff --git a/src/Servers/Kestrel/Transport.Sockets/src/SocketConnectionFactoryOptions.cs b/src/Servers/Kestrel/Transport.Sockets/src/SocketConnectionFactoryOptions.cs index 35ce2bd8fd75..403f6fc108de 100644 --- a/src/Servers/Kestrel/Transport.Sockets/src/SocketConnectionFactoryOptions.cs +++ b/src/Servers/Kestrel/Transport.Sockets/src/SocketConnectionFactoryOptions.cs @@ -33,9 +33,9 @@ internal SocketConnectionFactoryOptions(SocketTransportOptions transportOptions) /// The number of I/O queues used to process requests. Set to 0 to directly schedule I/O to the ThreadPool. /// /// - /// Defaults to rounded down and clamped between 1 and 16. + /// Defaults to a value based on and limited to . /// - public int IOQueueCount { get; set; } = Math.Min(Environment.ProcessorCount, 16); + public int IOQueueCount { get; set; } = Internal.IOQueue.DefaultCount; /// /// Wait until there is data available to allocate a buffer. Setting this to false can increase throughput at the cost of increased memory usage. diff --git a/src/Servers/Kestrel/Transport.Sockets/src/SocketTransportOptions.cs b/src/Servers/Kestrel/Transport.Sockets/src/SocketTransportOptions.cs index a307465447ad..ad1a877df63c 100644 --- a/src/Servers/Kestrel/Transport.Sockets/src/SocketTransportOptions.cs +++ b/src/Servers/Kestrel/Transport.Sockets/src/SocketTransportOptions.cs @@ -28,9 +28,9 @@ static SocketTransportOptions() /// The number of I/O queues used to process requests. Set to 0 to directly schedule I/O to the ThreadPool. /// /// - /// Defaults to rounded down and clamped between 1 and 16. + /// Defaults to a value based on and limited to . /// - public int IOQueueCount { get; set; } = Math.Min(Environment.ProcessorCount, 16); + public int IOQueueCount { get; set; } = Internal.IOQueue.DefaultCount; /// /// Wait until there is data available to allocate a buffer. Setting this to false can increase throughput at the cost of increased memory usage.