简体   繁体   中英

What is the use of Cancellation token here

I've the following chunk of code :

using (var cancelSource = new CancellationTokenSource()) 
{
    Task[] tasks = null;

    var cancelToken = cancelSource.Token;
    tasks = new[]
    {
        Task.Run(async () => await ThrowAfterAsync("C", cancelToken, 1000)) //<---
    };
    await Task.Delay(howLongSecs * 1000); // <---
    cancelSource.Cancel();
    await Task.WhenAll(tasks);
}

Where ThrowAfterAsync have this :

private async Task ThrowAfterAsync(string taskId, CancellationToken cancelToken, int afterMs)
{
    await Task.Delay(afterMs, cancelToken);
    var msg = $"{taskId} throwing after {afterMs}ms";
    Console.WriteLine(msg);
    throw new ApplicationException(msg);
}

Resharper is suggesting me that I can use the overload of Task.Run() with cancellation token like this :

Task.Run(async () => await ThrowAfterAsync("C", cancelToken, 1000), cancelToken)

But why ? What is the benefit of doing this over the first version, without the cancellation token as parameter ?

In this specific case, there is no point. In general, you'd want to do as it suggests because, by passing the token to Task.Run it can avoid even scheduling the operation in the first place if the token is cancelled before the operation even has a chance to start , but in your case you're creating the token and you know it won't be cancelled when you start the operation.

But the reason you don't need to pass the token to Task.Run is because the code starting that task is the operation responsible for cancelling the token , and so it knows that the token isn't cancelled yet. Normally you'd be accepting a token from elsewhere, and you wouldn't know if/when it was cancelled.

All that said, there's no reason to even use Task.Run at all . You can just write:

tasks = new[] { ThrowAfterAsync("C", cancelToken, 1000) };

It will have the same behavior but without needlessly starting a new thread just to start the asynchronous operation.

Next, your code will never return in less than howLongSecs seconds , even if the operation finishes before then, because of how you've structured your code. You should simply provide the timeout to the cancellation token source and let it take care of canceling the token at the right time, it won't delay the rest of your method if the operation finishes before the cancellation should happen, so your whole method can just be written as:

using (var cancelSource = new CancellationTokenSource(Timespan.FromSeconds(howLongSecs))) 
{
    await ThrowAfterAsync("C", cancelToken, 1000)
}

Resharper sees that you are using a method ( Task.Run ) which has overload which accepts CancellationToken , you have instance of CancellationToken in scope, but you do not use that overload which accepts a token. It does not perform any extensive analysys of your code - it's as simple as that. You can easily verify this with this code:

class Program {
    static void Main() {
        CancellationToken ct;
        Test("msg"); // will suggest to pass CancellationToken here
    }

    private static void Test(string msg) {

    }

    private static void Test(string msg, CancellationToken ct) {

    }
}

Yes the code itself is strange and you don't need to wrap your async in Task.Run at all, but I won't touch that since you asked just why Resharper suggests that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM