Task.WaitAll 不等待任务完成 [英] Task.WaitAll not waiting for task to complete

查看:34
本文介绍了Task.WaitAll 不等待任务完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在尝试找出新的(现在可能不是那么新,但对我来说是新的)Task 用 C# 异步编程时,我遇到了一个问题,我花了一些时间才弄清楚,我不知道为什么.

While trying to figure out the new (maybe not so new now, but new to me, anyway) Task asynchronous programming in C#, I ran into a problem that took me a bit to figure out, and I'm not sure why.

我已经解决了这个问题,但我仍然不确定为什么它是一个问题.我只是想我会分享我的经验,以防有人遇到同样的情况.

I have fixed the problem, but I am still not sure why it was a problem to begin with. I just thought I'd share my experience in case anyone out there runs into the same situation.

如果有任何专家想告诉我问题的原因,那将是非常棒的,非常感谢.我总是喜欢知道为什么有些东西不起作用!

If any gurus would like to inform me of the cause of the problem, that'd be wonderful and much appreciated. I always like knowing just why something doesn't work!

我做了一个测试任务,如下:

I made a test task, as follows:

Random rng = new Random((int)DateTime.UtcNow.Ticks);
int delay = rng.Next(1500, 15000);
Task<Task<object>> testTask = Task.Factory.StartNew<Task<object>>(
    async (obj) =>
        {
            DateTime startTime = DateTime.Now;
            Console.WriteLine("{0} - Starting test task with delay of {1}ms.", DateTime.Now.ToString("h:mm:ss.ffff"), (int)obj);
            await Task.Delay((int)obj);
            Console.WriteLine("{0} - Test task finished after {1}ms.", DateTime.Now.ToString("h:mm:ss.ffff"), (DateTime.Now - startTime).TotalMilliseconds);
            return obj;
        },
        delay
    );
Task<Task<object>>[] tasks = new Task<Task<object>>[] { testTask };

Task.WaitAll(tasks);
Console.WriteLine("{0} - Finished waiting.", DateTime.Now.ToString("h:mm:ss.ffff"));

// make console stay open till user presses enter
Console.ReadLine();

然后我运行该应用程序以查看它吐出的内容.以下是一些示例输出:

And then I ran the application to see what it spat out. Here is some sample output:

6:06:15.5661 - 以 3053 毫秒的延迟启动测试任务.
6:06:15.5662 - 完成等待.
6:06:18.5743 - 测试任务在 3063.235 毫秒后完成.

6:06:15.5661 - Starting test task with delay of 3053ms.
6:06:15.5662 - Finished waiting.
6:06:18.5743 - Test task finished after 3063.235ms.

如您所见,Task.WaitAll(tasks); 语句没有做太多事情.它在继续执行之前总共等待了 1 毫秒.

As you can see, the Task.WaitAll(tasks); statement didn't do much. It waited a grand total of 1 millisecond before continuing execution.

我已经在下面回答了我自己的问题"——但正如我上面所说的——如果有比我更了解的人愿意解释为什么这不起作用,请做!(我认为它可能与方法的执行逐步退出"有关,一旦它到达 await 运算符 - 然后在等待完成后退回...但我可能错了)

I have answered my own "question" below - but as I said above - if anyone more knowledgeable than I would care to explain why this doesn't work, please do! (I think it might have something to do with the execution 'stepping-out' of the method once it reaches an await operator - then stepping back in once the awaiting is done... But I am probably wrong)

推荐答案

您应该避免将 Task.Factory.StartNew 与 async-await 一起使用.您应该改用 Task.Run.

You should avoid using Task.Factory.StartNew with async-await. You should use Task.Run instead.

异步方法返回一个 Task,异步委托也是如此.Task.Factory.StartNew 还返回一个 Task,其结果是委托参数的结果.因此,当一起使用时,它会返回 Task>>.

An async method returns a Task<T>, an async delegate does as well. Task.Factory.StartNew also returns a Task<T>, where its result is the result of the delegate parameter. So when used together it returns a Task<Task<T>>>.

这个 Task> 所做的就是执行委托,直到有任务要返回,也就是到达第一个等待的时候.如果您只等待该任务完成,您就不会等待整个方法,而只是等待第一个 await 之前的部分.

All that this Task<Task<T>> does is execute the delegate until there's a task to return, which is when the first await is reached. If you only wait for that task to complete you aren't waiting for the whole method, just the part before the first await.

您可以通过使用 Task.Unwrap 来解决这个问题,它会创建一个 Task 来表示 Task>>:

You can fix that by using Task.Unwrap which creates a Task<T> that represents that Task<Task<T>>>:

Task<Task> wrapperTask = Task.Factory.StartNew(...);
Task actualTask = wrapperTask.Unwrap();
Task.WaitAll(actualTask);

这篇关于Task.WaitAll 不等待任务完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆