您当前的位置: 首页 > 

寒冰屋

暂无认证

  • 1浏览

    0关注

    2286博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

如何延迟一个 Task 的执行 ?

寒冰屋 发布时间:2021-12-26 21:41:35 ,浏览量:1

咨询区
  • Bruno Lopes

我想实现一个可以在延迟 Xms 后执行一个 task 的需求,并要求能够实现在 xms 之前取消 task 的执行,我的参考代码如下:

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);

虽然用 Sleep + ContinueWith 的方式可以实现,但我觉得还不够完美,请问是否有更好的办法?

回答区
  • valentasm

你可以用 WaitOne 的另一个重载方法: Token.WaitHandle.WaitOne(int32 milliseconds), 它比Thread.Sleep(xxx) 🐂👃的地方在于,可以实现让当前的线程等待xxx秒同时也可以在 xxxs 内被取消。

参考如下代码:

static void Main(string[] args)
{
    var tokenSource = new CancellationTokenSource();
    var token = tokenSource.Token;

    var task = Task.Factory.StartNew(() =>
    {
        // wait for 5 seconds or user hit Enter key cancel the task
        token.WaitHandle.WaitOne(5000);
        token.ThrowIfCancellationRequested();
        Console.WriteLine("Task started its work");
    });

    Console.WriteLine("Press 'Enter' key to cancel your task");

    Console.Read();

    tokenSource.Cancel();
}

  • jyoung

如果你的程序是 .NET 4.5 以上或者 .netcore 的话,可以使用 Task.Delay() 来实现,非常方便,参考如下代码:

        static void Main(string[] args)
        {
            var tokenSource = new CancellationTokenSource();
            var token = tokenSource.Token;

            tokenSource.Cancel();

            Task.Delay(1000, token).ContinueWith(t =>
                {
                    Console.WriteLine("hello world!");
                },token);

            Console.ReadLine();
        }

  • Dan Bryant

你可以在底层用 timer 作为调度机制,下面是我的完整代码实现。

 public static Task StartDelayTask(int delay, CancellationToken token)
    {
        var source = new TaskCompletionSource();
        Timer timer = null;

        timer = new Timer(s =>
        {
            source.TrySetResult(null);
            timer.Dispose();
        }, null, delay, -1);
        token.Register(() => source.TrySetCanceled());

        return source.Task;
    }

    public static Task ContinueAfterDelay
      (this Task task, 
           int delay, Action continuation, 
           CancellationToken token)
    {
        var source = new TaskCompletionSource();
        Timer timer = null;

        var startTimer = new Action(t =>
        {
            timer = new Timer(s =>
            {
                source.TrySetResult(null);
                timer.Dispose();
            },null,delay,-1);
        });

        task.ContinueWith
          (startTimer, 
           token, 
           TaskContinuationOptions.OnlyOnRanToCompletion, 
           TaskScheduler.Current);
        token.Register(() => source.TrySetCanceled());
        return source.Task.ContinueWith(continuation, token);
    }

点评区

三种方式都很好,不过我个人更倾向于用 Task.Delay() ,学习了。

关注
打赏
1665926880
查看更多评论
立即登录/注册

微信扫码登录

0.0419s