Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CancellationToken: why not to use AsyncLocal context instead of passing parameter to every async method?

I see microsoft enforces this pattern for async methods:

async Task<object> DoMyOperationAsync(int par1, string par2,..., CancellationToken token=default(CancellationToken))
{
   ...
   CancellationToken.ThrowIfRequested();
   ...
}

Every single method should have that ugly CancellationToken token=default(CancellationToken) parameter even though most of the time it's not even being used, but just passed through at best.

Why instead of this we cannot just use some sort of CancellationTokenContext, and use it in methods that actually need it?

public class CancellationTokenContext
{
    static AsyncLocal<CancellationToken> asyncContext = new AsyncLocal<CancellationToken>();

    public static CancellationToken Current {
        get {
            return asyncContext.Value;
        }
        set {
            asyncContext.Value = value;
        }
    }

    public static void ThrowIfRequested() {
        Current.ThrowIfCancellationRequested();
    }
}


public class MyClassWithAsyncMethod{

    public async Task<object> DoMyOperationAsync(int par1, string par2,...)
    {
        ...
        CancellationTokenContext.ThrowIfRequested();
        ...
    }

}

like image 501
Philipp Munin Avatar asked Oct 15 '22 12:10

Philipp Munin


1 Answers

The main reason for not using AsyncLocal is that it's much slower. In fact, it's a dictionary lookup, so it should be approximate 20x slower (~ 20ns vs 1ns).

One other factor is: explicit is usually better than implicit. Though I agree it's a very annoying part of async implementation.

like image 180
Alex Yakunin Avatar answered Oct 30 '22 02:10

Alex Yakunin