正确的方法来延迟任务的开始

Bru*_*pes 53 .net c# task-parallel-library

我想安排一个任务以x ms开始,并能够在它开始之前取消它(或者只是在任务开始时).

第一次尝试就像是

var _cancelationTokenSource = new CancellationTokenSource();

var token = _cancelationTokenSource.Token;
Task.Factory.StartNew(() =>
    {
        token.ThrowIfCancellationRequested();
        Thread.Sleep(100);
        token.ThrowIfCancellationRequested();
    }).ContinueWith(t =>
    {
        token.ThrowIfCancellationRequested();
        DoWork();
        token.ThrowIfCancellationRequested();
    }, token);
Run Code Online (Sandbox Code Playgroud)

但我觉得应该有一个更好的方法,因为这会在睡眠中耗尽一个线程,在此期间它可以被取消.

我还有什么其他选择?

Oha*_*der 28

Damien_The_Unbeliever提到的那样,Async CTP包括Task.Delay.幸运的是,我们有Reflector:

public static class TaskEx
{
    static readonly Task _sPreCompletedTask = GetCompletedTask();
    static readonly Task _sPreCanceledTask = GetPreCanceledTask();

    public static Task Delay(int dueTimeMs, CancellationToken cancellationToken)
    {
        if (dueTimeMs < -1)
            throw new ArgumentOutOfRangeException("dueTimeMs", "Invalid due time");
        if (cancellationToken.IsCancellationRequested)
            return _sPreCanceledTask;
        if (dueTimeMs == 0)
            return _sPreCompletedTask;

        var tcs = new TaskCompletionSource<object>();
        var ctr = new CancellationTokenRegistration();
        var timer = new Timer(delegate(object self)
        {
            ctr.Dispose();
            ((Timer)self).Dispose();
            tcs.TrySetResult(null);
        });
        if (cancellationToken.CanBeCanceled)
            ctr = cancellationToken.Register(delegate
                                                 {
                                                     timer.Dispose();
                                                     tcs.TrySetCanceled();
                                                 });

        timer.Change(dueTimeMs, -1);
        return tcs.Task;
    }

    private static Task GetPreCanceledTask()
    {
        var source = new TaskCompletionSource<object>();
        source.TrySetCanceled();
        return source.Task;
    }

    private static Task GetCompletedTask()
    {
        var source = new TaskCompletionSource<object>();
        source.TrySetResult(null);
        return source.Task;
    }
}
Run Code Online (Sandbox Code Playgroud)


sko*_*ima 19

由于.NET 4.5现已发布,因此有一种非常简单的内置方式来延迟任务:只需使用Task.Delay().在幕后,它使用ohadsc反编译的实现.


Dam*_*ver 8

未来的正确答案可能是Task.Delay.但是,目前只能通过Async CTP(在CTP中,它在TaskEx而不是Task)上使用.

不幸的是,因为它只在CTP中,所以也没有很多很好的文档链接.

  • `.Delay()`和其他基于TAP的方法现在可通过[Async Targeting Pack]在Async CTP之外的.NET 4.0中使用(http://www.microsoft.com/en-us/download/details的.aspx?ID = 29576).忽略声称它仅适用于VS11,它在VS2010上运行得非常好,因为它只是一个库. (4认同)