C# Task.Delay() 未按预期运行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18672638/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 12:54:34  来源:igfitidea点击:

Task.Delay() not behaving as expected

c#multithreadingtask-parallel-library

提问by trailmax

Task.Delay() not behaving as expected or rather I'm not understanding what it is supposed to do. I'm trying to get my head around Tasks in C# and how to replace Threads in my implementation.

Task.Delay() 没有按预期运行,或者我不明白它应该做什么。我正在尝试了解TaskC# 中的 s 以及如何Thread在我的实现中替换s。

What I'm trying to do is something like this:

我想要做的是这样的:

  • While true
    • print a line
    • wait for a second,
    • If condition is satisfied, exit loop, otherwise keep looping
  • 虽然是真的
    • 打印一行
    • 等一下,
    • 如果条件满足,退出循环,否则继续循环

I've got that implemented with Threads fine, but all cool kids say I should be using Task, and don't touch Thread.

我已经用 Threads 很好地实现了它,但是所有很酷的孩子都说我应该使用 Task,而不要碰 Thread。

So for the code I have this (Ignore [Test]- this just a convenient way to try out things)

所以对于代码我有这个(忽略[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;
            }
        }
    }

When I run this, the test finishes in milliseconds, not in 20 seconds as I would expect. If I replace Task.Delay()with Thread.Sleep(), everything works as expected and I get the printout once a second. I have tried adding asyncand awaitinto ChattyWriter(), but not only it did not add a 1 second delay, it only printed only one line instead of 20.

当我运行它时,测试在几毫秒内完成,而不是像我预期的那样在 20 秒内完成。如果我替换Task.Delay()Thread.Sleep(),一切都会按预期进行,并且我会每秒获得一次打印输出。我试过添加asyncawait进入ChattyWriter(),但它不仅没有添加 1 秒的延迟,它只打印了一行而不是 20。

What am I doing wrong?

我究竟做错了什么?

Probably It'll help to describe what I'm doing: my project works with external API (RESTful) and after I request some tasks to happen, I need to poll the API to check if the task has been completed. External tasks can be long running: 1-15 minutes. So I need some delay between checking for completion. And there could be many different concurrent processes executed with multiple external tasks. I understand, that if I use Thread.Sleep()when polling, other processes on the same Threadwill be blocked for no good reason.

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

采纳答案by slfan

Task.Delayreturns a Taskobject on which you have to wait. Otherwise the following code will be executed immediately. Therfore you have to declare your method as async. Then you can await Task.Delay

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

You have to interrupt your calling thread somehow. The unit test would terminate and the background thread as well. But if you call this method from the UI, the UI will not get blocked.

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

By calling Waiton an asynchronous method you will end up with a deadlock. See herefor more information.

通过调用Wait异步方法,您最终会陷入死锁。请参阅此处了解更多信息。

回答by Cristian Lupascu

Task.Delay(1000);creates an async task that will complete after a second, but the execution of the current method will continue in parallel.

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

In order to wait for the task to complete first, you could replace

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

Task.Delay(1000);

with

Task.Delay(1000).Wait();

回答by Pandacoon

Task.Delay() actually creates a task, so you just need to wait for it.

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

Try this

尝试这个

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