我试图了解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;
}));
}
答案 0 :(得分:6)
我的问题是:这对这种方法有什么影响(或者 它没有)?
一些差异
async
中使用Task.Run
委托表示您实际运行Task<Task>
。 Task.Run
异步识别并为您解开内部任务这一事实对您隐藏,Task.Factory.StartNew
没有做过当您使用Task.Run
的异步委托时,您创建一个新线程,然后在点击await Task.Delay
后产生控制权。延续将在任意线程池线程上运行。另外,委托由编译器转换为状态机。
使用普通委托,您创建一个线程,同步阻止它5秒钟,然后在您离开的位置继续。没有国家机器,没有屈服。
所以,即使它在Task.Delay上产生等待,在这种情况下有什么用,因为线程无论如何都是一个孤立的线程 不用于任何其他东西,即使它只使用Thread.Sleep, 线程仍然会将上下文切换为屈服于其他线程 处理器。
async
与Task.Run
的使用可以在您想要同时执行CPU和IO绑定工作时,都在专用线程中。您认为在异步委托产生之后,它会在任意线程上返回。但是,如果您没有使用Task.Run
,并且从附加了自定义同步上下文的线程(例如WinformsSynchronizationContext)执行async
方法,那么await
之后的任何工作都可以除非您使用ConfigureAwait(false)
。
说实话,我还没有看到正确使用Task.Run
和async
的许多场景。但有时它确实有意义。
答案 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;
}