Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
Change some internal async Task methods to be async ValueTask
Browse files Browse the repository at this point in the history
We have some internal and private `async Task` methods that are only ever `await`ed.  Today there's no benefit to making them `async ValueTask` methods, so we've kept them as `async Task`.  However, if we end up changing the implementation of `async ValueTask` to pool underlying objects, there becomes a potential benefit to using `async ValueTask` for these instead of `async Task`.  This PR changes those in a variety of libraries where we care more about performance and allocations.  There are likely a few more methods we'd want to convert based on profiling, but I believe this represents the bulk of them.
  • Loading branch information
stephentoub committed Oct 9, 2019
1 parent fe8db47 commit feb040e
Show file tree
Hide file tree
Showing 23 changed files with 78 additions and 79 deletions.
20 changes: 10 additions & 10 deletions src/Common/src/System/Net/WebSockets/ManagedWebSocket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ private ValueTask SendFrameAsync(MessageOpcode opcode, bool endOfMessage, ReadOn
// Similarly, it should be rare that there are multiple outstanding calls to SendFrameAsync, but if there are, again
// fall back to the fallback path.
return cancellationToken.CanBeCanceled || !_sendFrameAsyncLock.Wait(0) ?
new ValueTask(SendFrameFallbackAsync(opcode, endOfMessage, payloadBuffer, cancellationToken)) :
SendFrameFallbackAsync(opcode, endOfMessage, payloadBuffer, cancellationToken) :
SendFrameLockAcquiredNonCancelableAsync(opcode, endOfMessage, payloadBuffer);
}

Expand Down Expand Up @@ -421,10 +421,10 @@ private ValueTask SendFrameLockAcquiredNonCancelableAsync(MessageOpcode opcode,
}
}

return new ValueTask(WaitForWriteTaskAsync(writeTask));
return WaitForWriteTaskAsync(writeTask);
}

private async Task WaitForWriteTaskAsync(ValueTask writeTask)
private async ValueTask WaitForWriteTaskAsync(ValueTask writeTask)
{
try
{
Expand All @@ -443,7 +443,7 @@ private async Task WaitForWriteTaskAsync(ValueTask writeTask)
}
}

private async Task SendFrameFallbackAsync(MessageOpcode opcode, bool endOfMessage, ReadOnlyMemory<byte> payloadBuffer, CancellationToken cancellationToken)
private async ValueTask SendFrameFallbackAsync(MessageOpcode opcode, bool endOfMessage, ReadOnlyMemory<byte> payloadBuffer, CancellationToken cancellationToken)
{
await _sendFrameAsyncLock.WaitAsync(cancellationToken).ConfigureAwait(false);
try
Expand Down Expand Up @@ -781,7 +781,7 @@ private async ValueTask<TWebSocketReceiveResult> ReceiveAsyncPrivate<TWebSocketR
/// <summary>Processes a received close message.</summary>
/// <param name="header">The message header.</param>
/// <returns>The received result message.</returns>
private async Task HandleReceivedCloseAsync(MessageHeader header, CancellationToken cancellationToken)
private async ValueTask HandleReceivedCloseAsync(MessageHeader header, CancellationToken cancellationToken)
{
lock (StateUpdateLock)
{
Expand Down Expand Up @@ -848,7 +848,7 @@ private async Task HandleReceivedCloseAsync(MessageHeader header, CancellationTo
}

/// <summary>Issues a read on the stream to wait for EOF.</summary>
private async Task WaitForServerToCloseConnectionAsync(CancellationToken cancellationToken)
private async ValueTask WaitForServerToCloseConnectionAsync(CancellationToken cancellationToken)
{
// Per RFC 6455 7.1.1, try to let the server close the connection. We give it up to a second.
// We simply issue a read and don't care what we get back; we could validate that we don't get
Expand Down Expand Up @@ -876,7 +876,7 @@ private async Task WaitForServerToCloseConnectionAsync(CancellationToken cancell

/// <summary>Processes a received ping or pong message.</summary>
/// <param name="header">The message header.</param>
private async Task HandleReceivedPingPongAsync(MessageHeader header, CancellationToken cancellationToken)
private async ValueTask HandleReceivedPingPongAsync(MessageHeader header, CancellationToken cancellationToken)
{
// Consume any (optional) payload associated with the ping/pong.
if (header.PayloadLength > 0 && _receiveBufferCount < header.PayloadLength)
Expand Down Expand Up @@ -949,7 +949,7 @@ private static bool IsValidCloseStatus(WebSocketCloseStatus closeStatus)
/// <param name="closeStatus">The close status code to use.</param>
/// <param name="error">The error reason.</param>
/// <param name="innerException">An optional inner exception to include in the thrown exception.</param>
private async Task CloseWithReceiveErrorAndThrowAsync(
private async ValueTask CloseWithReceiveErrorAndThrowAsync(
WebSocketCloseStatus closeStatus, WebSocketError error, Exception innerException = null)
{
// Close the connection if it hasn't already been closed
Expand Down Expand Up @@ -1132,7 +1132,7 @@ private async Task CloseAsyncPrivate(WebSocketCloseStatus closeStatus, string st
/// <param name="closeStatus">The close status to send.</param>
/// <param name="closeStatusDescription">The close status description to send.</param>
/// <param name="cancellationToken">The CancellationToken to use to cancel the websocket.</param>
private async Task SendCloseFrameAsync(WebSocketCloseStatus closeStatus, string closeStatusDescription, CancellationToken cancellationToken)
private async ValueTask SendCloseFrameAsync(WebSocketCloseStatus closeStatus, string closeStatusDescription, CancellationToken cancellationToken)
{
// Close payload is two bytes containing the close status followed by a UTF8-encoding of the status description, if it exists.

Expand Down Expand Up @@ -1193,7 +1193,7 @@ private void ConsumeFromBuffer(int count)
_receiveBufferOffset += count;
}

private async Task EnsureBufferContainsAsync(int minimumRequiredBytes, CancellationToken cancellationToken, bool throwOnPrematureClosure = true)
private async ValueTask EnsureBufferContainsAsync(int minimumRequiredBytes, CancellationToken cancellationToken, bool throwOnPrematureClosure = true)
{
Debug.Assert(minimumRequiredBytes <= _receiveBuffer.Length, $"Requested number of bytes {minimumRequiredBytes} must not exceed {_receiveBuffer.Length}");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,12 @@ public override Task WriteAsync(byte[] buffer, int offset, int count, Cancellati
EnsureNoActiveAsyncOperation();
EnsureNotDisposed();

return new ValueTask(cancellationToken.IsCancellationRequested ?
Task.FromCanceled<int>(cancellationToken) :
WriteAsyncMemoryCore(buffer, cancellationToken));
return cancellationToken.IsCancellationRequested ?
new ValueTask(Task.FromCanceled<int>(cancellationToken)) :
WriteAsyncMemoryCore(buffer, cancellationToken);
}

private async Task WriteAsyncMemoryCore(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken, bool isFinalBlock = false)
private async ValueTask WriteAsyncMemoryCore(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken, bool isFinalBlock = false)
{
AsyncOperationStarting();
try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ private void PurgeBuffers(bool disposing)
}
}

private async Task PurgeBuffersAsync()
private async ValueTask PurgeBuffersAsync()
{
// Same logic as PurgeBuffers, except with async counterparts.

Expand Down Expand Up @@ -809,12 +809,12 @@ internal ValueTask WriteAsyncMemory(ReadOnlyMemory<byte> buffer, CancellationTok
EnsureNoActiveAsyncOperation();
EnsureNotDisposed();

return new ValueTask(cancellationToken.IsCancellationRequested ?
Task.FromCanceled<int>(cancellationToken) :
WriteAsyncMemoryCore(buffer, cancellationToken));
return cancellationToken.IsCancellationRequested ?
new ValueTask(Task.FromCanceled<int>(cancellationToken)) :
WriteAsyncMemoryCore(buffer, cancellationToken);
}

private async Task WriteAsyncMemoryCore(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
private async ValueTask WriteAsyncMemoryCore(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
{
AsyncOperationStarting();
try
Expand All @@ -838,7 +838,7 @@ private async Task WriteAsyncMemoryCore(ReadOnlyMemory<byte> buffer, Cancellatio
/// <summary>
/// Writes the bytes that have already been deflated
/// </summary>
private async Task WriteDeflaterOutputAsync(CancellationToken cancellationToken)
private async ValueTask WriteDeflaterOutputAsync(CancellationToken cancellationToken)
{
Debug.Assert(_deflater != null && _buffer != null);
while (!_deflater.NeedsInput())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ private static void SetBasicAuthToken(HttpRequestMessage request, NetworkCredent
SetRequestAuthenticationHeaderValue(request, new AuthenticationHeaderValue(BasicScheme, base64AuthString), isProxyAuth);
}

private static async Task<bool> TrySetDigestAuthToken(HttpRequestMessage request, NetworkCredential credential, DigestResponse digestResponse, bool isProxyAuth)
private static async ValueTask<bool> TrySetDigestAuthToken(HttpRequestMessage request, NetworkCredential credential, DigestResponse digestResponse, bool isProxyAuth)
{
string parameter = await GetDigestTokenForCredential(credential, request, digestResponse).ConfigureAwait(false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ private enum ParsingState : byte

public override bool NeedsDrain => (_connection != null);

public override async Task<bool> DrainAsync(int maxDrainBytes)
public override async ValueTask<bool> DrainAsync(int maxDrainBytes)
{
Debug.Assert(_connection != null);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationTo
// Don't write if nothing was given, especially since we don't want to accidentally send a 0 chunk,
// which would indicate end of body. Instead, just ensure no content is stuck in the buffer.
connection.FlushAsync() :
new ValueTask(WriteChunkAsync(connection, buffer));
WriteChunkAsync(connection, buffer);

return task;

static async Task WriteChunkAsync(HttpConnection connection, ReadOnlyMemory<byte> buffer)
static async ValueTask WriteChunkAsync(HttpConnection connection, ReadOnlyMemory<byte> buffer)
{
// Write chunk length in hex followed by \r\n
await connection.WriteHexInt32Async(buffer.Length).ConfigureAwait(false);
Expand All @@ -47,7 +47,7 @@ static async Task WriteChunkAsync(HttpConnection connection, ReadOnlyMemory<byte
}
}

public override async Task FinishAsync()
public override async ValueTask FinishAsync()
{
// Send 0 byte chunk to indicate end, then final CrLf
HttpConnection connection = GetConnectionOrThrow();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ private ReadOnlyMemory<byte> ReadFromConnectionBuffer(int maxBytesToRead)

public override bool NeedsDrain => (_connection != null);

public override async Task<bool> DrainAsync(int maxDrainBytes)
public override async ValueTask<bool> DrainAsync(int maxDrainBytes)
{
Debug.Assert(_connection != null);
Debug.Assert(_contentBytesRemaining > 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationTo
// that are still buffered.
HttpConnection connection = GetConnectionOrThrow();
Debug.Assert(connection._currentRequest != null);
return new ValueTask(connection.WriteAsync(buffer));
return connection.WriteAsync(buffer);
}

public override Task FinishAsync()
public override ValueTask FinishAsync()
{
_connection = null;
return Task.CompletedTask;
return default;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ public ValueTask<int> RequestCreditAsync(int amount, CancellationToken cancellat
var waiter = new Waiter { Amount = amount };
(_waiters ??= new Queue<Waiter>()).Enqueue(waiter);

return new ValueTask<int>(cancellationToken.CanBeCanceled ?
waiter.WaitWithCancellationAsync(cancellationToken) :
waiter.Task);
return cancellationToken.CanBeCanceled ?
waiter.WaitWithCancellationAsync(cancellationToken) :
new ValueTask<int>(waiter.Task);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public Http2Connection(HttpConnectionPool pool, Stream stream)

private object SyncObject => _httpStreams;

public async Task SetupAsync()
public async ValueTask SetupAsync()
{
_outgoingBuffer.EnsureAvailableSpace(s_http2ConnectionPreface.Length +
FrameHeader.Size + (FrameHeader.SettingLength * 2) +
Expand Down Expand Up @@ -165,7 +165,7 @@ public async Task SetupAsync()
_ = ProcessIncomingFramesAsync();
}

private async Task EnsureIncomingBytesAsync(int minReadBytes)
private async ValueTask EnsureIncomingBytesAsync(int minReadBytes)
{
if (NetEventSource.IsEnabled) Trace($"{nameof(minReadBytes)}={minReadBytes}");
if (_incomingBuffer.ActiveLength >= minReadBytes)
Expand Down Expand Up @@ -321,7 +321,7 @@ private Http2Stream GetStream(int streamId)
}
}

private async Task ProcessHeadersFrame(FrameHeader frameHeader)
private async ValueTask ProcessHeadersFrame(FrameHeader frameHeader)
{
if (NetEventSource.IsEnabled) Trace($"{frameHeader}");
Debug.Assert(frameHeader.Type == FrameType.Headers);
Expand Down Expand Up @@ -783,7 +783,7 @@ private void EndWrite(bool forceFlush)
}
}

private async Task AcquireWriteLockAsync(CancellationToken cancellationToken)
private async ValueTask AcquireWriteLockAsync(CancellationToken cancellationToken)
{
Task acquireLockTask = _writerLock.WaitAsync(cancellationToken);
if (!acquireLockTask.IsCompletedSuccessfully)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ public async Task SendRequestBodyAsync(CancellationToken cancellationToken)
// We can either get 100 response from server and send body
// or we may exceed timeout and send request body anyway.
// If we get response status >= 300, we will not send the request body.
public async Task<bool> WaitFor100ContinueAsync(CancellationToken cancellationToken)
public async ValueTask<bool> WaitFor100ContinueAsync(CancellationToken cancellationToken)
{
Debug.Assert(_request.Content != null);
if (NetEventSource.IsEnabled) Trace($"Waiting to send request body content for 100-Continue.");
Expand Down Expand Up @@ -969,7 +969,7 @@ private void CopyTrailersToResponseMessage(HttpResponseMessage responseMessage)
}
}

private async Task SendDataAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
private async ValueTask SendDataAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
{
ReadOnlyMemory<byte> remaining = buffer;

Expand Down Expand Up @@ -1047,11 +1047,11 @@ private ValueTask GetWaiterTask(CancellationToken cancellationToken)
// if it is cancelable, then register for the cancellation callback, allocate a task for the asynchronously
// completing case, etc.
return cancellationToken.CanBeCanceled ?
new ValueTask(GetCancelableWaiterTask(cancellationToken)) :
GetCancelableWaiterTask(cancellationToken) :
new ValueTask(this, _waitSource.Version);
}

private async Task GetCancelableWaiterTask(CancellationToken cancellationToken)
private async ValueTask GetCancelableWaiterTask(CancellationToken cancellationToken)
{
using (cancellationToken.UnsafeRegister(s =>
{
Expand Down Expand Up @@ -1213,7 +1213,7 @@ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationTo
return new ValueTask(Task.FromException(new ObjectDisposedException(nameof(Http2WriteStream))));
}

return new ValueTask(http2Stream.SendDataAsync(buffer, cancellationToken));
return http2Stream.SendDataAsync(buffer, cancellationToken);
}

public override Task FlushAsync(CancellationToken cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ private void ConsumeFromRemainingBuffer(int bytesToConsume)
_readOffset += bytesToConsume;
}

private async Task WriteHeadersAsync(HttpHeaders headers, string cookiesFromContainer)
private async ValueTask WriteHeadersAsync(HttpHeaders headers, string cookiesFromContainer)
{
if (headers.HeaderStore != null)
{
Expand Down Expand Up @@ -278,7 +278,7 @@ private async Task WriteHeadersAsync(HttpHeaders headers, string cookiesFromCont
}
}

private async Task WriteHostHeaderAsync(Uri uri)
private async ValueTask WriteHostHeaderAsync(Uri uri)
{
await WriteBytesAsync(KnownHeaders.Host.AsciiBytesWithColonSpace).ConfigureAwait(false);

Expand Down Expand Up @@ -773,7 +773,7 @@ private CancellationTokenRegistration RegisterCancellation(CancellationToken can

private static bool IsLineEmpty(ArraySegment<byte> line) => line.Count == 0;

private async Task SendRequestContentAsync(HttpRequestMessage request, HttpContentWriteStream stream, CancellationToken cancellationToken)
private async ValueTask SendRequestContentAsync(HttpRequestMessage request, HttpContentWriteStream stream, CancellationToken cancellationToken)
{
// Now that we're sending content, prohibit retries on this connection.
_canRetry = false;
Expand Down Expand Up @@ -986,7 +986,7 @@ private void WriteToBuffer(ReadOnlyMemory<byte> source)
_writeOffset += source.Length;
}

private async Task WriteAsync(ReadOnlyMemory<byte> source)
private async ValueTask WriteAsync(ReadOnlyMemory<byte> source)
{
int remaining = _writeBuffer.Length - _writeOffset;

Expand Down Expand Up @@ -1063,10 +1063,10 @@ private ValueTask WriteWithoutBufferingAsync(ReadOnlyMemory<byte> source)

// There's data in the write buffer and the data we're writing doesn't fit after it.
// Do two writes, one to flush the buffer and then another to write the supplied content.
return new ValueTask(FlushThenWriteWithoutBufferingAsync(source));
return FlushThenWriteWithoutBufferingAsync(source);
}

private async Task FlushThenWriteWithoutBufferingAsync(ReadOnlyMemory<byte> source)
private async ValueTask FlushThenWriteWithoutBufferingAsync(ReadOnlyMemory<byte> source)
{
await FlushAsync().ConfigureAwait(false);
await WriteToStreamAsync(source).ConfigureAwait(false);
Expand Down Expand Up @@ -1405,7 +1405,7 @@ private void Fill()
}

// Throws IOException on EOF. This is only called when we expect more data.
private async Task FillAsync()
private async ValueTask FillAsync()
{
Debug.Assert(_readAheadTask == null);

Expand Down Expand Up @@ -1598,7 +1598,7 @@ private async ValueTask<int> ReadBufferedAsyncCore(Memory<byte> destination)
return bytesToCopy;
}

private async Task CopyFromBufferAsync(Stream destination, int count, CancellationToken cancellationToken)
private async ValueTask CopyFromBufferAsync(Stream destination, int count, CancellationToken cancellationToken)
{
Debug.Assert(count <= _readLength - _readOffset);

Expand Down Expand Up @@ -1768,7 +1768,7 @@ private void CompleteResponse()
}
}

public async Task DrainResponseAsync(HttpResponseMessage response)
public async ValueTask DrainResponseAsync(HttpResponseMessage response)
{
Debug.Assert(_inUse);

Expand Down
Loading

0 comments on commit feb040e

Please sign in to comment.