Add inline scheduler option for Sockets transport (#24638)
This commit is contained in:
parent
512a49c401
commit
c92eaa28f4
|
|
@ -63,7 +63,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
|
||||||
_trace,
|
_trace,
|
||||||
_options.MaxReadBufferSize,
|
_options.MaxReadBufferSize,
|
||||||
_options.MaxWriteBufferSize,
|
_options.MaxWriteBufferSize,
|
||||||
_options.WaitForDataBeforeAllocatingBuffer);
|
_options.WaitForDataBeforeAllocatingBuffer,
|
||||||
|
_options.UnsafePreferInlineScheduling);
|
||||||
|
|
||||||
socketConnection.Start();
|
socketConnection.Start();
|
||||||
return socketConnection;
|
return socketConnection;
|
||||||
|
|
|
||||||
|
|
@ -37,11 +37,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
|
||||||
|
|
||||||
internal SocketConnection(Socket socket,
|
internal SocketConnection(Socket socket,
|
||||||
MemoryPool<byte> memoryPool,
|
MemoryPool<byte> memoryPool,
|
||||||
PipeScheduler scheduler,
|
PipeScheduler transportScheduler,
|
||||||
ISocketsTrace trace,
|
ISocketsTrace trace,
|
||||||
long? maxReadBufferSize = null,
|
long? maxReadBufferSize = null,
|
||||||
long? maxWriteBufferSize = null,
|
long? maxWriteBufferSize = null,
|
||||||
bool waitForData = true)
|
bool waitForData = true,
|
||||||
|
bool useInlineSchedulers = false)
|
||||||
{
|
{
|
||||||
Debug.Assert(socket != null);
|
Debug.Assert(socket != null);
|
||||||
Debug.Assert(memoryPool != null);
|
Debug.Assert(memoryPool != null);
|
||||||
|
|
@ -60,7 +61,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
|
||||||
// On *nix platforms, Sockets already dispatches to the ThreadPool.
|
// On *nix platforms, Sockets already dispatches to the ThreadPool.
|
||||||
// Yes, the IOQueues are still used for the PipeSchedulers. This is intentional.
|
// Yes, the IOQueues are still used for the PipeSchedulers. This is intentional.
|
||||||
// https://github.com/aspnet/KestrelHttpServer/issues/2573
|
// https://github.com/aspnet/KestrelHttpServer/issues/2573
|
||||||
var awaiterScheduler = IsWindows ? scheduler : PipeScheduler.Inline;
|
var awaiterScheduler = IsWindows ? transportScheduler : PipeScheduler.Inline;
|
||||||
|
|
||||||
|
var applicationScheduler = PipeScheduler.ThreadPool;
|
||||||
|
if (useInlineSchedulers)
|
||||||
|
{
|
||||||
|
transportScheduler = PipeScheduler.Inline;
|
||||||
|
awaiterScheduler = PipeScheduler.Inline;
|
||||||
|
applicationScheduler = PipeScheduler.Inline;
|
||||||
|
}
|
||||||
|
|
||||||
_receiver = new SocketReceiver(_socket, awaiterScheduler);
|
_receiver = new SocketReceiver(_socket, awaiterScheduler);
|
||||||
_sender = new SocketSender(_socket, awaiterScheduler);
|
_sender = new SocketSender(_socket, awaiterScheduler);
|
||||||
|
|
@ -68,8 +77,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
|
||||||
maxReadBufferSize ??= 0;
|
maxReadBufferSize ??= 0;
|
||||||
maxWriteBufferSize ??= 0;
|
maxWriteBufferSize ??= 0;
|
||||||
|
|
||||||
var inputOptions = new PipeOptions(MemoryPool, PipeScheduler.ThreadPool, scheduler, maxReadBufferSize.Value, maxReadBufferSize.Value / 2, useSynchronizationContext: false);
|
var inputOptions = new PipeOptions(MemoryPool, applicationScheduler, transportScheduler, maxReadBufferSize.Value, maxReadBufferSize.Value / 2, useSynchronizationContext: false);
|
||||||
var outputOptions = new PipeOptions(MemoryPool, scheduler, PipeScheduler.ThreadPool, maxWriteBufferSize.Value, maxWriteBufferSize.Value / 2, useSynchronizationContext: false);
|
var outputOptions = new PipeOptions(MemoryPool, transportScheduler, applicationScheduler, maxWriteBufferSize.Value, maxWriteBufferSize.Value / 2, useSynchronizationContext: false);
|
||||||
|
|
||||||
var pair = DuplexPipe.CreateConnectionPair(inputOptions, outputOptions);
|
var pair = DuplexPipe.CreateConnectionPair(inputOptions, outputOptions);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
|
||||||
}
|
}
|
||||||
|
|
||||||
var connection = new SocketConnection(acceptSocket, _memoryPool, _schedulers[_schedulerIndex], _trace,
|
var connection = new SocketConnection(acceptSocket, _memoryPool, _schedulers[_schedulerIndex], _trace,
|
||||||
_options.MaxReadBufferSize, _options.MaxWriteBufferSize, _options.WaitForDataBeforeAllocatingBuffer);
|
_options.MaxReadBufferSize, _options.MaxWriteBufferSize, _options.WaitForDataBeforeAllocatingBuffer,
|
||||||
|
_options.UnsafePreferInlineScheduling);
|
||||||
|
|
||||||
connection.Start();
|
connection.Start();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
|
||||||
|
|
||||||
public long? MaxWriteBufferSize { get; set; } = 64 * 1024;
|
public long? MaxWriteBufferSize { get; set; } = 64 * 1024;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inline application and transport continuations instead of dispatching to the threadpool.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This will run application code on the IO thread which is why this is unsafe.
|
||||||
|
/// It is recommended to set the DOTNET_SYSTEM_NET_SOCKETS_INLINE_COMPLETIONS environment variable to '1' when using this setting to also inline the completions
|
||||||
|
/// at the runtime layer as well.
|
||||||
|
/// This setting can make performance worse if there is expensive work that will end up holding onto the IO thread for longer than needed.
|
||||||
|
/// Test to make sure this setting helps performance.
|
||||||
|
/// </remarks>
|
||||||
|
public bool UnsafePreferInlineScheduling { get; set; }
|
||||||
|
|
||||||
internal Func<MemoryPool<byte>> MemoryPoolFactory { get; set; } = System.Buffers.SlabMemoryPoolFactory.Create;
|
internal Func<MemoryPool<byte>> MemoryPoolFactory { get; set; } = System.Buffers.SlabMemoryPoolFactory.Create;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue