Task.Delay()的行为不符合预期

时间:2013-09-07 11:05:24

标签: c# multithreading task-parallel-library

Task.Delay()的行为不符合预期,或者说我不理解它应该做什么。我试图了解C#中的Task以及如何在我的实现中替换Thread

我想做的是这样的事情:

  • 虽然如此
    • 打印一行
    • 等一下,
    • 如果满足条件,则退出循环,否则保持循环

我已经使用Threads实现了这一点,但是所有很酷的孩子都说我应该使用Task,而不要触摸Thread。

所以对于代码我有这个(忽略[Test] - 这只是一种方便的尝试方法)

    [Test]
    public void ChattyTask()
    {
        var chattyTask = new Task(ChattyWriter);
        chattyTask.Start();
        chattyTask.Wait();
    }

    public void ChattyWriter()
    {
        int count = 0;
        while (true)
        {
            var message = String.Format("Chatty Writer number {0}", count);
            Trace.WriteLine(message);
            count++;
            Task.Delay(1000);

            if (count >= 20)
            {
                break;
            }
        }
    }

当我运行它时,测试以毫秒为单位完成,而不是像我期望的那样在20秒内完成。如果我用Task.Delay()替换Thread.Sleep(),一切都按预期工作,我会每秒打印一次。我已尝试将asyncawait添加到ChattyWriter(),但不仅仅添加了1秒延迟,它只打印了一行而不是20行。

我做错了什么?

可能有助于描述我正在做的事情:我的项目使用外部API(RESTful),在我请求执行某些任务之后,我需要轮询API以检查任务是否已完成。外部任务可以长时间运行:1-15分钟。所以我需要在检查完成之间有一些延迟。并且可能有许多不同的并发进程与多个外部任务一起执行。我理解,如果我在轮询时使用Thread.Sleep(),那么同一Thread上的其他进程将被无法正常阻止。

3 个答案:

答案 0 :(得分:33)

Task.Delay返回您必须等待的Task对象。否则,将立即执行以下代码。因此,您必须将方法声明为async。然后你可以等待Task.Delay

public async Task ChattyWriter()
{
    int count = 0;
    while (true)
    {
        var message = String.Format("Chatty Writer number {0}", count);
        Trace.WriteLine(message);
        count++;
        await Task.Delay(1000);
           ...
    }
}

你必须以某种方式打断你的调用线程。单元测试将终止,后台线程也将终止。但是如果你从UI调用这个方法,UI就不会被阻止。

通过在异步方法上调用Wait,最终会出现死锁。有关详细信息,请参阅here

答案 1 :(得分:20)

Task.Delay(1000);创建一个异步任务,该任务将在一秒钟后完成,但当前方法的执行将并行继续。

为了等待任务先完成,您可以替换

Task.Delay(1000);

Task.Delay(1000).Wait();

答案 2 :(得分:1)

Task.Delay()实际上创建了一个任务,所以你只需要等待它。

试试这个

        public static void ChattyWriter()
    {
        int count = 0;
        while (true)
        {
            var message = String.Format("Chatty Writer number {0}", count);
            Console.WriteLine(message);
            count++;
            var t = Task.Delay(1000);
            t.Wait();

            if (count >= 20)
            {
                break;
            }
        }
    }