Skip to content

Reduce overheads of NullOperationListener.Delay#54517

Merged
sharwell merged 3 commits intodotnet:mainfrom
stephentoub:nulllistenerdelay
Jul 2, 2021
Merged

Reduce overheads of NullOperationListener.Delay#54517
sharwell merged 3 commits intodotnet:mainfrom
stephentoub:nulllistenerdelay

Conversation

@stephentoub
Copy link
Copy Markdown
Member

This is showing up as a primary source of first-chance cancellation exceptions while creating projects in VS.

On .NET Framework 4.8:

Method Mean Allocated
CanceledWithAsync 13,006.369 ns 2,327 B
CanceledWithContinueWith 1,028.581 ns 1,051 B
Delay0WithAsync 62.790 ns 0 B
Delay0ContinueWith 6.936 ns 0 B
Delay1WithAsync 15,848,603.711 ns 640 B
Delay1ContinueWith 15,668,003.846 ns 512 B

On .NET 6.0:

Method Mean Allocated
CanceledWithAsync 8,368.800 ns 1,664 B
CanceledWithContinueWith 397.767 ns 696 B
Delay0WithAsync 17.956 ns 0 B
Delay0ContinueWith 6.066 ns 0 B
Delay1WithAsync 15,839,737.292 ns 404 B
Delay1ContinueWith 15,718,382.169 ns 406 B
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Running;
using System.Threading;
using System.Threading.Tasks;
using BenchmarkDotNet.Diagnosers;
using Perfolizer.Horology;
using BenchmarkDotNet.Columns;
using System.Globalization;
using BenchmarkDotNet.Reports;

[MemoryDiagnoser]
public class Program
{
    public static void Main(string[] args) =>
        BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args,
            DefaultConfig.Instance.WithSummaryStyle(new SummaryStyle(CultureInfo.InvariantCulture,
                printUnitsInHeader: false,
                sizeUnit: SizeUnit.B,
                timeUnit: TimeUnit.Nanosecond,
                printZeroValuesInContent: true)));

    [Benchmark]
    public Task CanceledWithAsync()
    {
        var cts = new CancellationTokenSource();
        Task<bool> t = DelayWithAsync(1_000_000, cts.Token);
        cts.Cancel();
        return t.ContinueWith(_ => _, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
    }

    [Benchmark]
    public Task CanceledWithContinueWith()
    {
        var cts = new CancellationTokenSource();
        Task<bool> t = DelayWithContinueWith(1_000_000, cts.Token);
        cts.Cancel();
        return t.ContinueWith(_ => _, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
    }

    [Benchmark]
    public Task<bool> Delay0WithAsync() => DelayWithAsync(0, default);

    [Benchmark]
    public Task<bool> Delay0ContinueWith() => DelayWithContinueWith(0, default);

    [Benchmark]
    public Task<bool> Delay1WithAsync() => DelayWithAsync(1, default);

    [Benchmark]
    public Task<bool> Delay1ContinueWith() => DelayWithContinueWith(1, default);

    private static async Task<bool> DelayWithAsync(int delay, CancellationToken cancellationToken)
    {
        await Task.Delay(delay, cancellationToken).ConfigureAwait(false);
        return true;
    }

    private static Task<bool> DelayWithContinueWith(int delay, CancellationToken cancellationToken)
    {
        if (cancellationToken.IsCancellationRequested)
        {
            return Task.FromCanceled<bool>(cancellationToken);
        }

        var t = Task.Delay(delay, cancellationToken);
        if (t.IsCompleted)
        {
            return t.Status == TaskStatus.RanToCompletion ?
                SpecializedTasks.True :
                Task.FromCanceled<bool>(cancellationToken);
        }

        return t.ContinueWith(
            _ => true,
            CancellationToken.None,
            TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.NotOnCanceled,
            TaskScheduler.Default);
    }

    class SpecializedTasks
    {
        public static readonly Task<bool> True = Task.FromResult(true);
    }
}

@stephentoub stephentoub requested a review from a team as a code owner July 1, 2021 17:34
@ghost ghost added the Area-IDE label Jul 1, 2021
@sharwell
Copy link
Copy Markdown
Contributor

sharwell commented Jul 1, 2021

I was literally right in the middle of this 🤣

This is showing up as a primary source of cancellation exceptions while creating projects in VS.
@CyrusNajmabadi
Copy link
Copy Markdown
Contributor

Is Delay0WithAsync meaningful? I'm curiosu the codepaths doing that.

@stephentoub
Copy link
Copy Markdown
Member Author

Is Delay0WithAsync meaningful?

Based on what I saw of current usage, I don't believe so. I included it in my local microbenchmarks just for completeness.

…ationListenerProvider+NullOperationListener.cs

Co-authored-by: CyrusNajmabadi <cyrus.najmabadi@gmail.com>
…ationListenerProvider+NullOperationListener.cs
@sharwell sharwell merged commit 1166b56 into dotnet:main Jul 2, 2021
@ghost ghost added this to the Next milestone Jul 2, 2021
@allisonchou allisonchou modified the milestones: Next, 17.0.P3 Jul 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants