取消.Net 4.0中的任务延迟

bub*_*ing 6 .net c# task-parallel-library

我目前正在尝试Task.Delay()在必须以.Net 4.0为目标的程序中实现.Net 4.5的替代方法.我在这个博客上找到了以下代码.

    /* You can write Task-based asynchronous methods by utilizing a TaskCompletionSource.
A TaskCompletionSource gives you a 'slave' Task that you can manually signal.
Calling SetResult() signals the task as complete, and any continuations kick off. */

void Main()
{    
    for (int i = 0; i < 10000; i++)
    {
        Task task = Delay (2000);
        task.ContinueWith (_ => "Done".Dump());
    }
}

Task Delay (int milliseconds)        // Asynchronous NON-BLOCKING method
{
    var tcs = new TaskCompletionSource<object>();
    new Timer (_ => tcs.SetResult (null)).Change (milliseconds, -1);
    return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)

Tasks对我来说相当新鲜. System.Threading.Timer并且TaskCompletionSource对我来说是全新的(截至今天),我正在与他们挣扎.除此之外,我想知道如何CancellationToken为此代码添加功能.我假设我可以Delay()像这样在方法中添加一个参数:

Task Delay (int milliseconds, CancellationToken token)        // Asynchronous NON-BLOCKING method
{
    var tcs = new TaskCompletionSource<object>();
    new Timer (_ => tcs.SetResult (null)).Change (milliseconds, -1);
    return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)

...但是,我在哪里放置检查令牌和退出方法的逻辑?在回调的某个地方?这甚至可能吗?

Jar*_*lls 4

我尝试尽可能少地更改您的代码,但这里有一个工作示例,其行为方式与 Task.Delay 相同。

需要注意的是,我使用了TrySetCanceled和 ,TrySetResult因为计时器可以在任务取消后完成。理想情况下你想停止计时器。

另请注意,取消的任务将引发TaskCanceledException

static void Main(string[] args)
{
    // A cancellation source that will cancel itself after 1 second
    var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(1));

    try
    {
        // This will only wait 1 second because as it will be cancelled.
        Task t = Delay(5000, cancellationTokenSource.Token);                
        t.Wait();
        Console.WriteLine("The task completed");
    }
    catch (AggregateException exception)
    {
        // Expecting a TaskCanceledException
        foreach (Exception ex in exception.InnerExceptions)
            Console.WriteLine("Exception: {0}", ex.Message);
    }
    Console.WriteLine("Done");
    Console.ReadLine();
}

private static Task Delay(int milliseconds, CancellationToken token)
{
    var tcs = new TaskCompletionSource<object>();
    token.Register(() => tcs.TrySetCanceled());
    Timer timer = new Timer(_ => tcs.TrySetResult(null));
    timer.Change(milliseconds, -1);            
    return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)

多读一点你的问题。如果您需要 Task.Delay 并且您的目标是 .NET 4.0,那么您应该使用http://www.nuget.org/packages/Microsoft.Bcl.Async/中的 Microsoft Async nuget 包,它包含该方法TaskEx.Delay

  • 这是一个很好的双重答案。实际上,我的项目中已经安装了 Microsoft.Bcl.Async,但我没有意识到他们将这些方法隐藏在 TaskEx 下。感谢您对上下文的详细解释和 BCL 扩展的提示。 (2认同)