使用和不使用 await 运算符的任务执行

Bud*_*ril 6 c# task-parallel-library async-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);
        }
Run Code Online (Sandbox Code Playgroud)

我已经删除了 await 操作符,并在行上设置了一个断点Console.WriteLine(completed);。为什么在这个断点等待2-3分钟后,任务没有完成,没有故障?我在任务的代码中设置了一个断点并且异常被删除,所以任务必须至少被标记为错误或完成......

dta*_*enc 7

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

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

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

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

代码:

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);  
Run Code Online (Sandbox Code Playgroud)

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

请记住,正如其他人所说,立即使用awaited Task.Run()几乎总是一个错误。请记住,重点async/await是释放当前线程,这样它就不会做无用的等待。如果您执行 aTask.Run后接 anawait您还没有取得任何成就,因为您只是在释放当前线程(将其放回线程池中),但是Task.Run()它将从线程池中占用一个线程。从概念上讲,您所做的一切都是将您的工作从一个线程 ID 转移到另一个线程 ID,而没有真正的收益(即使您的工作Task.Run受 CPU 限制)。

在这种情况下,您最好什么都不做Task.Run,而只是在当前线程上同步完成工作。