I wouldn't expect an async benefit in this particular command line harness, but neither would I expect such a large penalty.
On my machine, under repeated runs, for a 46 MB input file (Git-2.27.0-64-bit.exe) the async version is consistently around 7x slower.
- I find it surprising that disposing the
outputFile
stream takes so long (averaging arouund 16 seconds) even though it is preceded by an explicitFlush
/FlushAsync
- however that is the case for both the synchronous and asynchronous calls, so not a difference between them. - In the async version
ConfigureAwait(false)
doesn't appear to make much difference in this particular harness (and I didn't really expect it to) - Playing with buffer size in
CopyTo
/CopyToAsync
didn't seem to narrow the gap any.
Example Asynchronous results:
\Base64\bin\Release\netcoreapp3.1>Base64.exe
WriteFile completed in 00:02:40.5583442
Flushing outputFile
Flush outputFile completed in 00:00:00.0010565
disposing outputFile
disposed outputFile in 00:00:15.7304240
disposing base64Stream
disposed base64Stream in 00:00:00.0029926
disposing inputFile
disposed inputFile in 00:00:00.0002473
disposing base64Transform
disposed base64Transform in 00:00:00.0020258
Total Elapsed: 00:02:56.3132804
Example Synchronous results:
\Base64\Base64\bin\Release\netcoreapp3.1>Base64.exe
WriteFile completed in 00:00:08.9381189
Flushing outputFile
Flush outputFile completed in 00:00:00.0016328
disposing outputFile
disposed outputFile in 00:00:16.5799980
disposing base64Stream
disposed base64Stream in 00:00:00.0046472
disposing inputFile
disposed inputFile in 00:00:00.0019350
disposing base64Transform
disposed base64Transform in 00:00:00.0014333
Total Elapsed: 00:00:25.5501378
Asynchronous test
static async Task Main(string[] args)
{
var totalStopWatch = new Stopwatch();
totalStopWatch.Start();
var stopWatch = new Stopwatch();
stopWatch.Start();
using (var base64Transform = new ToBase64Transform())
{
await using (FileStream inputFile = new FileStream(@"Git-2.27.0-64-bit.exe", FileMode.Open, FileAccess.Read))
{
await using (CryptoStream base64Stream = new CryptoStream(inputFile, base64Transform, CryptoStreamMode.Read))
{
await using (FileStream outputFile = new FileStream($@"outfile{Guid.NewGuid()}.html", FileMode.CreateNew, FileAccess.Write))
{
await outputFile.WriteAsync(Encoding.UTF8.GetBytes(@"<!doctype html>
<html>
<head>
<title>base 64 encoding test</title>
</head>
<body>
<img alt=""Ok so not really an image."" src=""data:image/jpeg;base64,")).ConfigureAwait(false);
await base64Stream.CopyToAsync(outputFile, 8192).ConfigureAwait(false);
await outputFile.WriteAsync(Encoding.UTF8.GetBytes(@""" />
</body>
</html>
")).ConfigureAwait(false);
Console.WriteLine($"WriteFile completed in {stopWatch.Elapsed}");
stopWatch.Restart();
Console.WriteLine($"Flushing {nameof(outputFile)}");
await outputFile.FlushAsync().ConfigureAwait(false);
Console.WriteLine($"Flush {nameof(outputFile)} completed in {stopWatch.Elapsed}");
stopWatch.Restart();
Console.WriteLine($"disposing {nameof(outputFile)}");
}
Console.WriteLine($"disposed outputFile in {stopWatch.Elapsed}");
stopWatch.Restart();
Console.WriteLine($"disposing {nameof(base64Stream)}");
}
Console.WriteLine($"disposed base64Stream in {stopWatch.Elapsed}");
stopWatch.Restart();
Console.WriteLine($"disposing {nameof(inputFile)}");
}
Console.WriteLine($"disposed inputFile in {stopWatch.Elapsed}");
stopWatch.Restart();
Console.WriteLine($"disposing {nameof(base64Transform)}");
}
Console.WriteLine($"disposed base64Transform in {stopWatch.Elapsed}");
Console.WriteLine($"Total Elapsed: {totalStopWatch.Elapsed}");
}
Synchronous test
static void Main(string[] args)
{
var totalStopWatch = new Stopwatch();
totalStopWatch.Start();
var stopWatch = new Stopwatch();
stopWatch.Start();
using (var base64Transform = new ToBase64Transform())
{
using (FileStream inputFile = new FileStream(@"Git-2.27.0-64-bit.exe", FileMode.Open, FileAccess.Read))
{
using (CryptoStream base64Stream = new CryptoStream(inputFile, base64Transform, CryptoStreamMode.Read))
{
using (FileStream outputFile = new FileStream($@"outfile{Guid.NewGuid()}.html", FileMode.CreateNew, FileAccess.Write))
{
outputFile.Write(Encoding.UTF8.GetBytes(@"<!doctype html>
<html>
<head>
<title>base 64 encoding test</title>
</head>
<body>
<img alt=""Ok so not really an image."" src=""data:image/jpeg;base64,"));
base64Stream.CopyTo(outputFile, 8192);
outputFile.Write(Encoding.UTF8.GetBytes(@""" />
</body>
</html>
"));
Console.WriteLine($"WriteFile completed in {stopWatch.Elapsed}");
stopWatch.Restart();
Console.WriteLine($"Flushing {nameof(outputFile)}");
outputFile.Flush();
Console.WriteLine($"Flush {nameof(outputFile)} completed in {stopWatch.Elapsed}");
stopWatch.Restart();
Console.WriteLine($"disposing {nameof(outputFile)}");
}
Console.WriteLine($"disposed outputFile in {stopWatch.Elapsed}");
stopWatch.Restart();
Console.WriteLine($"disposing {nameof(base64Stream)}");
}
Console.WriteLine($"disposed base64Stream in {stopWatch.Elapsed}");
stopWatch.Restart();
Console.WriteLine($"disposing {nameof(inputFile)}");
}
Console.WriteLine($"disposed inputFile in {stopWatch.Elapsed}");
stopWatch.Restart();
Console.WriteLine($"disposing {nameof(base64Transform)}");
}
Console.WriteLine($"disposed base64Transform in {stopWatch.Elapsed}");
Console.WriteLine($"Total Elapsed: {totalStopWatch.Elapsed}");
}