Skip to content

await ValueTask performance #11803

@hpbieker

Description

@hpbieker

I did some performance testing for async-await on a completed ValueTask and compared it to a Task.CompletedTask. I see that for Task.CompletedTask it does not matter if I bypass await if I check the Task for IsCompletedSuccessfully, but for ValueTask it has significant performance impact (3x). Is there a missing optimization in the async code generated for async-await when using ValueTask?

BenchmarkDotNet=v0.11.3, OS=Windows 7 SP1 (6.1.7601.0)
Intel Core i5-6300U CPU 2.40GHz (Skylake), 1 CPU, 4 logical and 2 physical cores
Frequency=2437558 Hz, Resolution=410.2466 ns, Timer=TSC
.NET Core SDK=2.2.100
  [Host]     : .NET Core 2.2.0 (CoreCLR 4.6.27110.04, CoreFX 4.6.27110.04), 64bit RyuJIT
  Job-OUSAWM : .NET Core 2.2.0 (CoreCLR 4.6.27110.04, CoreFX 4.6.27110.04), 64bit RyuJIT

WarmupCount=1

                                 Method |       Mean |     Error |    StdDev | Gen 0/1k Op | Gen 1/1k Op | Gen 2/1k Op | Allocated Memory/Op |
--------------------------------------- |-----------:|----------:|----------:|------------:|------------:|------------:|--------------------:|
                              ValueTask | 1,031.7 ns | 16.990 ns | 15.892 ns |           - |           - |           - |                   - |
     ValueTaskIfIsCompletedSuccessfully |   291.5 ns |  2.743 ns |  2.291 ns |           - |           - |           - |                   - |
 CompletedTaskIfIsCompletedSuccessfully |   277.7 ns |  5.460 ns |  6.288 ns |           - |           - |           - |                   - |
                          CompletedTask |   319.5 ns |  4.782 ns |  3.993 ns |           - |           - |           - |                   - |
        [Benchmark]
        public async Task ValueTask()
        {
            for (int i = 0; i < 100; i++)
                await new ValueTask();
        }

        [Benchmark]
        public async Task ValueTaskIfIsCompletedSuccessfully()
        {
            for (int i = 0; i < 100; i++)
            {
                var valueTask = new ValueTask();
                if (!valueTask.IsCompletedSuccessfully)
                    await valueTask;
            }
        }

        [Benchmark]
        public async Task CompletedTaskIfIsCompletedSuccessfully()
        {
            for (int i = 0; i < 100; i++)
            {
                var task = Task.CompletedTask;
                if (!task.IsCompletedSuccessfully)
                    await task;
            }
        }

        [Benchmark]
        public async Task CompletedTask()
        {
            for (int i = 0; i < 100; i++)
                await Task.CompletedTask;
        }

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions