它有什么区别 - 使用Task.Run(vs默认操作委托)运行'async'操作委托?

时间:2015-07-23 09:50:01

标签: c# .net async-await .net-4.5

我试图了解async / await,并认为我对使用情况了解不多。但是仍然不太清楚在下面的场景中实际的好处是什么。

查看Task.Run用法。第一种方法使用普通委托并使用Thread.Sleep,但第二种方法使用'async'委托和Task.Delay。

我的问题是:这对这种方法有什么影响(或者它没有)?

该方法本身是一种异步方法。代码正在创建一个单独的线程(通过Task.Run),除了执行该委托之外,该线程没有其他任何操作。因此,即使它在Task.Delay上产生等待,在这种情况下有什么用处,因为线程无论如何都是一个孤立的线程没有用于任何其他东西,即使它只是使用Thread.Sleep,线程仍然是上下文切换到处理器的其他线程。

// The task thread uses a async delegate
public async Task<bool> RetrySendEmail(MailMessage message)
{
      bool emailSent = false;
      await (Task.Run(***async ()*** =>
      {
            for (int i = 0; i < 3; i++)
            {
                 if (emailSent)
                      break;
                 else
                      // Wait for 5 secs before trying again
                      ***await Task.Delay(5000);***

                 try
                 {
                      Smtphost.Send(message);
                      emailSent = true;
                      break;
                 }
                 catch (Exception e) { emailSent = false; // log; }
            }
            return emailSent;
      }));
}

// The task thread uses a normal delegate 
public async Task<bool> RetrySendEmail(MailMessage message)
{
      bool emailSent = false;
      await (Task.Run(***()*** =>
      {
            for (int i = 0; i < 3; i++)
            {
                 if (emailSent)
                      break;
                 else
                      // Wait for 5 secs before trying again
                      ***Thread.Sleep(5000);***

                 try
                 {
                      Smtphost.Send(message);
                      emailSent = true;
                      break;
                 }
                 catch (Exception e){ emailSent = false; // log; }
            }
                 return emailSent;
        }));
}

2 个答案:

答案 0 :(得分:6)

  

我的问题是:这对这种方法有什么影响(或者   它没有)?

一些差异

  1. async中使用Task.Run委托表示您实际运行Task<Task>Task.Run异步识别并为您解开内部任务这一事实对您隐藏,Task.Factory.StartNew没有做过
  2. 当您使用Task.Run的异步委托时,您创建一个新线程,然后在点击await Task.Delay后产生控制权。延续将在任意线程池线程上运行。另外,委托由编译器转换为状态机。

    使用普通委托,您创建一个线程,同步阻止它5秒钟,然后在您离开的位置继续。没有国家机器,没有屈服。

  3.   

    所以,即使它在Task.Delay上产生等待,在这种情况下有什么用,因为线程无论如何都是一个孤立的线程   不用于任何其他东西,即使它只使用Thread.Sleep,   线程仍然会将上下文切换为屈服于其他线程   处理器。

    asyncTask.Run的使用可以在您想要同时执行CPU和IO绑定工作时,都在专用线程中。您认为在异步委托产生之后,它会在任意线程上返回。但是,如果您没有使用Task.Run,并且从附加了自定义同步上下文的线程(例如WinformsSynchronizationContext)执行async方法,那么await之后的任何工作都可以除非您使用ConfigureAwait(false)

    ,否则将回退到UI消息循环

    说实话,我还没有看到正确使用Task.Runasync的许多场景。但有时它确实有意义。

答案 1 :(得分:3)

不同之处在于你浪费了一个线程及其分配的时间片。

当您阻止线程5秒钟时,该线程无法在系统的其他部分中使用以执行实际的CPU工作。它还创建了一个上下文切换,因为该线程无法执行任何其他操作。

当您使用Task.Delay而不是Thread.Sleep释放该线程时,线程可以返回ThreadPool,执行等待任务并执行它。

当你释放线程时,你可以使你的应用程序更具可扩展性和效率,因为它需要更少的资源来完成相同的工作或相同数量的资源来完成更多的工作。

如果您的操作非常异步,则无需使用Task.Run(除非您需要后台线程)。您只需调用该方法并等待返回的任务:

public async Task<bool> RetrySendEmail(MailMessage message)
{
    bool emailSent = false;
    for (int i = 0; i < 3; i++)
    {
         if (emailSent)
              break;
         else
              await Task.Delay(5000);

         try
         {
              Smtphost.Send(message);
              emailSent = true;
              break;
         }
         catch (Exception e) { emailSent = false; // log; }
    }
    return emailSent;
}