取消等待自己

时间:2015-02-09 21:08:48

标签: c# async-await

我有以下示例代码:

public static async Task Async()
{
    CancellationTokenSource source = new CancellationTokenSource();
    source.CancelAfter(500);
    Stopwatch sw = Stopwatch.StartNew();
    await RunThread(ExpensiveOperation, source.Token);
    sw.Stop();
    Console.WriteLine(sw.Elapsed);
}

public static async Task RunThread(Action act, CancellationToken token)
{   //modify this method to handle cancelling the token during the following await
    await Task.Run(act); //Task.Run(act, token) doesn't help
}

public static void ExpensiveOperation()
{
    Thread.Sleep(1000); //simulates CPU expensive operation
}

现在,如何通过注册正在取消的任务来修改RunThread方法以实际停止等待长任务,并在500毫秒之后返回,而不是等待{{的实际完成1}}?

1 个答案:

答案 0 :(得分:3)

您应该将令牌传递给操作本身,并不时检查它:

public static async Task RunThread(Action<CancellationToken> act, CancellationToken token)
{   
    await Task.Run(() => act(token), token);
}

public static void ExpensiveOperation(CancellationToken token)
{
    for (int i = 0; i < 10; i++)
    {
        token.ThrowIfCancellationRequested();
        Thread.Sleep(100);
    }
}

您还会将令牌传递给Task.Run,以便返回的Task知道它已被取消,而不仅仅是出现故障。

如果您无法从ExpensiveOperation内取消(要么您无法更改代码,要么它实际上是异步操作而非同步操作),请使用WithCancellation扩展方法:

static Task WithCancellation(this Task task, CancellationToken cancellationToken)
{
    return task.IsCompleted
        ? task
        : task.ContinueWith(
            completedTask => completedTask.GetAwaiter().GetResult(),
            cancellationToken,
            TaskContinuationOptions.ExecuteSynchronously,
            TaskScheduler.Default);
}

public static async Task RunThread(Action act, CancellationToken token)
{
    await Task.Run(act).WithCancellation(token);
}

请注意,这种方法实际上并没有取消操作,只是让代码流的行为就像它一样。

相关问题