有和没有await操作符的任务执行



我昨天问了一个问题,答案很好。但是现在我正试图理解await的作用以及任务执行是如何工作的。

我读过关于await的内容:await操作符应用于异步方法中的任务,以暂停该方法的执行,直到等待的任务完成。任务表示正在进行的工作(来自msdn站点)。

Task.run: Run方法允许您在单个方法调用中创建和执行任务,并且是StartNew方法(来自msdn站点)的更简单的替代方法。

现在,加上代码:
        public async Task YourFunc()
        {
            Exception error = null;
            try
            {
               var task = Task.Run(() =>
                         {
                             Thread.Sleep(3000);
                             throw new ArgumentException("test argument exception");
                         });
                var completed = task.IsCompleted;
                var faulted = task.IsFaulted;
                Console.WriteLine(completed);
                Console.WriteLine(faulted);
            }
            catch (Exception ex)
            {
                error = ex;
            }
            this.MigrationProcessCompleted(error);
        }

我已经删除了等待操作符,并在Console.WriteLine(completed);上设置了一个断点。为什么即使在此断点等待2-3分钟后,任务仍未完成且未发生故障?我在任务的代码中设置了一个断点,并抛出了异常,因此必须将任务标记为错误或至少完成……

没有人真正回答你的问题。如果等待超过3秒,您可以合理地期望看到task.isCompletedtask.isFaulted为真。

你的期望没有错。这里的问题只是调试器是如何工作的。当您在该断点处停止等待时,所有其他线程也都停止了,因此没有任何进展,并且还没有抛出异常。

这只是调试的一个怪癖,如果你想看到你期望的结果,你有几个选项:

    冻结线程而不是使用断点。为了做到这一点,在var task=Task.Run()之后放一个断点,然后在调试器中打开你的"线程"窗口。找到当前线程(黄色箭头)右键单击它并选择"冻结",然后按F8或点击继续让应用程序继续运行。3-4秒后,点击调试器上的"暂停"按钮,再次双击冻结的线程。你现在可以检查task.IsCompletedtask.IsFaulted的值,它们应该是真的。
  1. 检查任务前添加超时:
代码:

var task = Task.Run(() =>{
            Thread.Sleep(3000);
            throw new ArgumentException("test argument exception");
        });
        Thread.Sleep(5000);
        var completed = task.IsCompleted;
        var faulted = task.IsFaulted;
        Console.WriteLine("Completed ::" + completed);
        Console.WriteLine("Faulted ::" + faulted);  

现在您可以在Thread.Sleep(5000)之后放置一个断点,并确认任务是错误的/完成的。

请记住,正如其他人所说,立即使用awaited Task.Run()的用例几乎总是错误的。请记住,async/await的全部要点是释放当前线程,这样它就不会做无用的等待。如果您在Task.Run之后执行await,那么您没有取得任何成就,因为您只是释放了当前线程(将其放回线程池中),但是Task.Run()将从线程池中占用一个线程。从概念上讲,您所做的一切都是将您的工作从一个线程id移动到另一个线程id,而没有真正的收益(即使Task.Run中的工作是cpu绑定的)。

在这种情况下,你最好不做Task.Run,只是在当前线程上同步地做工作。

最新更新