【问题标题】:C# Task.Run does not await action variableC# Task.Run 不等待动作变量
【发布时间】:2018-11-26 19:55:19
【问题描述】:

查看示例代码。

Console.WriteLine("start")
Task.Run(async () =>
{
    await Task.Delay(3000);
});
Console.WriteLine("end");

// result 
// start [3s delay] end

有效! 但下面的代码不起作用。

Action action = async () =>
{
    await Task.Delay(3000);
};
Console.WriteLine("start")
Task.Run(action);
Console.WriteLine("end");

// result
// start [without delay] end

为什么Task.Run 不等待异步操作变量?

编辑 -------------

我很抱歉。我写错了代码。 这是正确的代码。

我在 VS 2017 的 C# Interactive 上测试它

Console.WriteLine("start");
await Task.Run(async () =>
{
    await Task.Delay(3000);
});
Console.WriteLine("end");

Action action = async () =>
{
    await Task.Delay(3000);
};
Console.WriteLine("start");
await Task.Run(action);
Console.WriteLine("end");

【问题讨论】:

  • 不确定您在哪里测试,但第一个示例不会等待延迟:dotnetfiddle.net/TP3J37
  • @CamiloTerevinto 对不起,我写错了代码。

标签: c# lambda async-await task


【解决方案1】:

会像这样工作,但不是那么明显:

Func<Task> action = async () =>
{
    await Task.Delay(3000);
};

Console.WriteLine("start");
await Task.Run(action);
Console.WriteLine("end");

【讨论】:

    【解决方案2】:

    当在没有等待的情况下使用Task.Run 时,这只会“一劳永逸”。代码执行不会等待它,它会在thread pool 提供thread 时立即运行它。

    通常,如果您想卸载一些工作并等待该工作完成,请创建一个单独的方法来返回 Task,然后是 await

    示例

    Console.WriteLine("start")
    await DoWorkAsync();
    Console.WriteLine("end");
    
    /////////
    private Task DoWorkAsync()
    {
      return Task.Run(async () =>
      {
         await Task.Delay(3000);
      });
    }
    

    请注意,不建议将方法主体包装到 Task 中并返回它,这通常会导致一些代码异味。

    Stephen Cleary 有关于Tasksasync/await 的详细信息。我会阅读这个:

    https://blog.stephencleary.com/2012/02/async-and-await.html

    【讨论】:

      【解决方案3】:

      使用 async 和 Tasks 的主要原因是让两个或多个方法同时运行。因此,您的方法将继续运行,并且在完成延迟后,将在延迟后调用任何内容,因为您在任务中运行了另一个异步函数。

      如果你运行这个方法,你会注意到

      完成

      将打印在其他作品的中间(这里的其他作品是for loop

      Console.WriteLine("start");
      Task.Run(async () =>
       {
           await Task.Delay(200);
            Console.WriteLine("Finished");
       });
      
       for(int i = 0; i < 500; i++)
          {
             Console.WriteLine(i);
          }
      Console.WriteLine("end");
      Console.ReadKey();
      

      由于某种原因,它在 dotnetfiddle 上无法按预期工作

      即使您没有在任务中运行异步,它们也会同时运行。

      看看这个例子:

       Console.WriteLine("start");
                  Task.Run(() =>
                  {
                      Task.Delay(2000).Wait(); // Will NOT wait !
                      Console.WriteLine("Finished");
                  });
      
                  for(int i = 0; i < 500; i++)
                  {
                      Console.WriteLine(i);
                  }
                  Console.WriteLine("end");
                  Console.ReadKey();
      

      它会继续,因为它在一个任务中

      但是,如果您希望该方法等待,首先:不要在任务上运行它。 第二:调用Wait()方法。

      喜欢:

      Console.WriteLine("start");
      
      Task.Delay(2000).Wait(); // It'll wait for 2 seconds before continue.
      
      for(int i = 0; i < 500; i++)
        {
           Console.WriteLine(i);
        }
       Console.WriteLine("end");
       Console.ReadKey();
      

      【讨论】:

        【解决方案4】:

        你可以试试这个:

        Action action = async () =>
                        {
                            await Task.Delay(3000);
                        };
                        Console.WriteLine("start");
                        Task.Run(action).Wait();                
                        Console.WriteLine("end");
        

        【讨论】:

        • 为什么这应该有效,因为它是问题的副本?顺便说一句:它不等待!
        • 不只是副本,我已经添加了.Wait();在第 6 行,它会为你工作,请尝试一下
        • 不工作:)。由于您正在执行一项任务,因此它不会等待。我之前添加了一个关于您的方法的示例,阅读我的答案,您会明白为什么它不等待。
        • @Kaj 你提供的是 Task.Delay(2000).Wait();这和我说的完全不同,兄弟。我的代码 100% 运行
        • 虽然你没有抓住重点。由于您正在执行一项任务,因此它不会等待!正如我尝试过的那样,它不会等待。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-12
        • 2020-06-19
        相关资源
        最近更新 更多