为什么.Net Core异步流操作比同步操作要慢得多?

时间:2020-09-02 03:00:47

标签: c# asynchronous .net-core .net-core-3.1

在这种特定的命令行工具中,我不会期望异步的好处,但是我也不会期望得到如此大的惩罚。

在我的机器上,反复运行后,对于46 MB的输入文件(Git-2.27.0-64-bit.exe),异步版本的运行速度始终慢7倍左右。

  • 我发现令人惊讶的是,即使在outputFile / Flush之前放置FlushAsync流也要花这么长时间(平均约16秒),但是对于同步调用和异步调用,两者之间没有区别。
  • 在异步版本ConfigureAwait(false)中,这种特定的功能似乎并没有多大区别(而且我确实没想到会如此)
  • CopyTo / CopyToAsync中的缓冲区大小似乎并没有缩小差距。

示例异步结果:

\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

示例同步结果:

\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

异步测试

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}");
}

同步测试

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}");
}

0 个答案:

没有答案