Fast-path async in HttpResponseStreamWriter
This commit is contained in:
parent
f6e20a38e2
commit
800c79c0e4
|
|
@ -3,7 +3,9 @@
|
|||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
@ -150,34 +152,66 @@ namespace Microsoft.AspNetCore.WebUtilities
|
|||
}
|
||||
}
|
||||
|
||||
public override async Task WriteAsync(char value)
|
||||
public override Task WriteAsync(char value)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(HttpResponseStreamWriter));
|
||||
return GetObjectDisposedTask();
|
||||
}
|
||||
|
||||
if (_charBufferCount == _charBufferSize)
|
||||
{
|
||||
await FlushInternalAsync(flushEncoder: false);
|
||||
return WriteAsyncAwaited(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Enough room in buffer, no need to go async
|
||||
_charBuffer[_charBufferCount] = value;
|
||||
_charBufferCount++;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task WriteAsyncAwaited(char value)
|
||||
{
|
||||
Debug.Assert(_charBufferCount == _charBufferSize);
|
||||
|
||||
await FlushInternalAsync(flushEncoder: false);
|
||||
|
||||
_charBuffer[_charBufferCount] = value;
|
||||
_charBufferCount++;
|
||||
}
|
||||
|
||||
public override async Task WriteAsync(char[] values, int index, int count)
|
||||
public override Task WriteAsync(char[] values, int index, int count)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(HttpResponseStreamWriter));
|
||||
return GetObjectDisposedTask();
|
||||
}
|
||||
|
||||
if (values == null)
|
||||
if (values == null || count == 0)
|
||||
{
|
||||
return;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
var remaining = _charBufferSize - _charBufferCount;
|
||||
if (remaining >= count)
|
||||
{
|
||||
// Enough room in buffer, no need to go async
|
||||
CopyToCharBuffer(values, ref index, ref count);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
else
|
||||
{
|
||||
return WriteAsyncAwaited(values, index, count);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task WriteAsyncAwaited(char[] values, int index, int count)
|
||||
{
|
||||
Debug.Assert(count > 0);
|
||||
Debug.Assert(_charBufferSize - _charBufferCount > count);
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
if (_charBufferCount == _charBufferSize)
|
||||
|
|
@ -186,22 +220,43 @@ namespace Microsoft.AspNetCore.WebUtilities
|
|||
}
|
||||
|
||||
CopyToCharBuffer(values, ref index, ref count);
|
||||
Debug.Assert(count == 0);
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task WriteAsync(string value)
|
||||
public override Task WriteAsync(string value)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(HttpResponseStreamWriter));
|
||||
return GetObjectDisposedTask();
|
||||
}
|
||||
|
||||
if (value == null)
|
||||
var count = value?.Length ?? 0;
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
var remaining = _charBufferSize - _charBufferCount;
|
||||
if (remaining >= count)
|
||||
{
|
||||
// Enough room in buffer, no need to go async
|
||||
CopyToCharBuffer(value);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
else
|
||||
{
|
||||
return WriteAsyncAwaited(value);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task WriteAsyncAwaited(string value)
|
||||
{
|
||||
var count = value.Length;
|
||||
|
||||
Debug.Assert(count > 0);
|
||||
Debug.Assert(_charBufferSize - _charBufferCount < count);
|
||||
|
||||
var index = 0;
|
||||
while (count > 0)
|
||||
{
|
||||
|
|
@ -231,7 +286,7 @@ namespace Microsoft.AspNetCore.WebUtilities
|
|||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(HttpResponseStreamWriter));
|
||||
return GetObjectDisposedTask();
|
||||
}
|
||||
|
||||
return FlushInternalAsync(flushEncoder: true);
|
||||
|
|
@ -306,6 +361,19 @@ namespace Microsoft.AspNetCore.WebUtilities
|
|||
}
|
||||
}
|
||||
|
||||
private void CopyToCharBuffer(string value)
|
||||
{
|
||||
Debug.Assert(_charBufferSize - _charBufferCount >= value.Length);
|
||||
|
||||
value.CopyTo(
|
||||
sourceIndex: 0,
|
||||
destination: _charBuffer,
|
||||
destinationIndex: _charBufferCount,
|
||||
count: value.Length);
|
||||
|
||||
_charBufferCount += value.Length;
|
||||
}
|
||||
|
||||
private void CopyToCharBuffer(string value, ref int index, ref int count)
|
||||
{
|
||||
var remaining = Math.Min(_charBufferSize - _charBufferCount, count);
|
||||
|
|
@ -336,5 +404,11 @@ namespace Microsoft.AspNetCore.WebUtilities
|
|||
index += remaining;
|
||||
count -= remaining;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private static Task GetObjectDisposedTask()
|
||||
{
|
||||
return Task.FromException(new ObjectDisposedException(nameof(HttpResponseStreamWriter)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue