-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Use System.Buffers in System.IO.FileSystem #5954
Conversation
while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0) | ||
{ | ||
await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Break read+write dependency? e.g.
byte[] buffer0 = ArrayPool<byte>.Shared.Rent(bufferSize);
byte[] buffer1 = ArrayPool<byte>.Shared.Rent(bufferSize);
return ArrayPoolCopyToAsyncInternal(source, destination, buffer0, buffer1, cancellationToken);
}
private static async Task ArrayPoolCopyToAsyncInternal(Stream source, Stream destination, byte[] buffer0, byte[] buffer1, CancellationToken cancellationToken)
{
try
{
int bytesRead;
Task<int> lastReadTask = source.ReadAsync(buffer0, 0, buffer0.Length, cancellationToken);
Task lastWriteTask = Task.CompletedTask;
bool otherBuffer = true;
while ((bytesRead = await lastReadTask.ConfigureAwait(false)) != 0)
{
lastReadTask = source.ReadAsync((otherBuffer ? buffer1 : buffer0), 0, (otherBuffer ? buffer1 : buffer0).Length, cancellationToken);
await lastWriteTask.ConfigureAwait(false);
lastWriteTask = destination.WriteAsync((otherBuffer ? buffer0 : buffer1), 0, bytesRead, cancellationToken);
otherBuffer = !otherBuffer;
}
await lastWriteTask.ConfigureAwait(false);
}
finally
{
ArrayPool<byte>.Shared.Return(buffer0);
ArrayPool<byte>.Shared.Return(buffer1);
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I considered that but decided against it for the same reasons we didn't do so in the original Stream.CopyToAsync implementation. It leads to interesting concurrency issues that we decided to avoid in these core methods. For example, if the two concurrent read and write operations throw, which exception should we propagate, and what does that mean if there were important information in the other? And if the operations would actually end up consuming a thread pool thread to do a synchronous operation, do we really want to potentially be blocking two thread pool threads rather than one? Etc. If someone determines that they would really benefit from such overlapping, they can make that decision at the app level (where they have the ability to measure impact at the app-level) and write the few lines like you have themselves. Thanks, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense
7a7ec87
to
0a4bfb5
Compare
LGTM |
@@ -107,7 +107,7 @@ internal void InitializeDeflater(Stream stream, bool leaveOpen, int windowBits, | |||
{ | |||
Debug.Assert(stream != null); | |||
if (!stream.CanWrite) | |||
throw new ArgumentException(SR.NotWriteableStream, "stream"); | |||
throw new ArgumentException(SR.NotSupported_UnreadableStream, "stream"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be NotSupported_UnwritableStream
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it should. Will fix.
LGTM! |
0a4bfb5
to
3512871
Compare
The default CopyToAsync on Stream uses an 80K temporary buffer, making it a good candidate for buffer pooling. But Stream is in mscorlib and can't rely on System.Buffers. So this commit introduces an implementation that streams in mscorlib can use, just by overriding CopyToAsync and delegating. It then uses that in DeflateStream, GZipStream, FileStream, PipeStream, and UnmanagedMemoryStream.
3512871
to
34ce38b
Compare
Use System.Buffers in System.IO.FileSystem
Use System.Buffers in System.IO.FileSystem Commit migrated from dotnet/corefx@f6cdaf2
ArrayPool<byte>.Shared
for its internal bufferArrayPool<byte>.Shared
until such type as the base Stream (in mscorlib) can use a pooled bufferHaving added that:
cc: @ericstij, @ianhays, @sokket, @KrzysztofCwalina
https://github.com/dotnet/corefx/issues/5598