Fast-path async in PagedBufferedTextWriter

This commit is contained in:
Ben Adams 2018-09-01 00:53:24 +01:00 committed by Ryan Nowak
parent fabe189470
commit 337bc462de
1 changed files with 55 additions and 8 deletions

View File

@ -28,14 +28,28 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
// Don't do anything. We'll call FlushAsync. // Don't do anything. We'll call FlushAsync.
} }
public override async Task FlushAsync() public override Task FlushAsync() => FlushAsyncCore();
// private non-virtual for internal calling
private Task FlushAsyncCore()
{ {
var length = _charBuffer.Length; var length = _charBuffer.Length;
if (length == 0) if (length == 0)
{ {
return;
// If nothing sync buffered return CompletedTask,
// so we can fast-path skip async state-machine creation
return Task.CompletedTask;
} }
return FlushAsyncAwaited();
}
private async Task FlushAsyncAwaited()
{
var length = _charBuffer.Length;
Debug.Assert(length > 0);
var pages = _charBuffer.Pages; var pages = _charBuffer.Pages;
var count = pages.Count; var count = pages.Count;
for (var i = 0; i < count; i++) for (var i = 0; i < count; i++)
@ -89,21 +103,54 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
_charBuffer.Append(value); _charBuffer.Append(value);
} }
public override async Task WriteAsync(char value) public override Task WriteAsync(char value)
{ {
await FlushAsync(); var flushTask = FlushAsyncCore();
// FlushAsyncCore will return CompletedTask if nothing sync buffered
// Fast-path and skip async state-machine if only a single async operation
return ReferenceEquals(flushTask, Task.CompletedTask) ?
_inner.WriteAsync(value) :
WriteAsyncAwaited(flushTask, value);
}
private async Task WriteAsyncAwaited(Task flushTask, char value)
{
await flushTask;
await _inner.WriteAsync(value); await _inner.WriteAsync(value);
} }
public override async Task WriteAsync(char[] buffer, int index, int count) public override Task WriteAsync(char[] buffer, int index, int count)
{ {
await FlushAsync(); var flushTask = FlushAsyncCore();
// FlushAsyncCore will return CompletedTask if nothing sync buffered
// Fast-path and skip async state-machine if only a single async operation
return ReferenceEquals(flushTask, Task.CompletedTask) ?
_inner.WriteAsync(buffer, index, count) :
WriteAsyncAwaited(flushTask, buffer, index, count);
}
private async Task WriteAsyncAwaited(Task flushTask, char[] buffer, int index, int count)
{
await flushTask;
await _inner.WriteAsync(buffer, index, count); await _inner.WriteAsync(buffer, index, count);
} }
public override async Task WriteAsync(string value) public override Task WriteAsync(string value)
{ {
await FlushAsync(); var flushTask = FlushAsyncCore();
// FlushAsyncCore will return CompletedTask if nothing sync buffered
// Fast-path and skip async state-machine if only a single async operation
return ReferenceEquals(flushTask, Task.CompletedTask) ?
_inner.WriteAsync(value) :
WriteAsyncAwaited(flushTask, value);
}
private async Task WriteAsyncAwaited(Task flushTask, string value)
{
await flushTask;
await _inner.WriteAsync(value); await _inner.WriteAsync(value);
} }