它有什么区别 - 运行 一个 'async' 动作委托和一个 Task.Run(与默认动作委托相比)?
What difference does it make - running an 'async' action delegate with a Task.Run (vs default action delegate)?
我正在努力了解 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;
}));
}
区别在于您正在浪费线程及其分配的时间片。
当您阻塞一个线程 5 秒后,该线程将无法在系统的其他部分用于执行实际 CPU 工作。它还会创建上下文切换,因为该线程无法执行任何其他操作。
当您使用 Task.Delay
而不是 Thread.Sleep
释放该线程时,线程可以 return 到 ThreadPool
,获取等待任务并执行它。
总的来说,当您释放线程时,您可以使您的应用程序更具可扩展性和效率,因为它需要更少的资源来完成相同的工作,或者需要相同数量的资源来完成更多的工作。
如果您的操作确实是异步的,则无需使用 Task.Run
(除非您需要后台线程)。您可以只调用该方法并等待 returned 任务:
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;
}
My question is : how does this make any difference to this method (or
it does not) ?
一些差异
- 在
Task.Run
中使用 async
委托意味着您实际上 运行 一个 Task<Task>
。 Task.Run
是异步感知并为你解包内部任务,这对你是隐藏的,这是 Task.Factory.StartNew
没有做的
当您将异步委托与 Task.Run
一起使用时,您会创建一个新线程,然后在您点击 await Task.Delay
后放弃控制权。延续将 运行 在任意线程池线程上。此外,委托由编译器转换为状态机。
使用普通委托,您创建一个线程,同步阻塞它 5 秒,然后从您离开的地方继续。没有国家机器,没有让步。
So, even if it yields with an await on Task.Delay, what is the use in this scenario, since the thread is anyways a isolated thread
not used for anything else and even if it just uses Thread.Sleep, the
thread would still context switch to yield to other threads for the
processor.
当您想同时执行 CPU 和 IO 绑定工作时,可以将 async
与 Task.Run
一起使用,所有这些都在专用线程中进行。您的想法是正确的,在异步委托产生之后,它 returns 在任意线程上。但是,如果您没有使用 Task.Run
,并且 async
方法是从附加了自定义同步上下文(例如 WinformsSynchronizationContext)的线程执行的,那么 await
之后的任何工作都会产生回到 UI 消息循环,除非你使用 ConfigureAwait(false)
.
说实话,Task.Run
和async
正确使用的场景我还没见过多少。但有时它确实有意义。
我正在努力了解 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;
}));
}
区别在于您正在浪费线程及其分配的时间片。
当您阻塞一个线程 5 秒后,该线程将无法在系统的其他部分用于执行实际 CPU 工作。它还会创建上下文切换,因为该线程无法执行任何其他操作。
当您使用 Task.Delay
而不是 Thread.Sleep
释放该线程时,线程可以 return 到 ThreadPool
,获取等待任务并执行它。
总的来说,当您释放线程时,您可以使您的应用程序更具可扩展性和效率,因为它需要更少的资源来完成相同的工作,或者需要相同数量的资源来完成更多的工作。
如果您的操作确实是异步的,则无需使用 Task.Run
(除非您需要后台线程)。您可以只调用该方法并等待 returned 任务:
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;
}
My question is : how does this make any difference to this method (or it does not) ?
一些差异
- 在
Task.Run
中使用async
委托意味着您实际上 运行 一个Task<Task>
。Task.Run
是异步感知并为你解包内部任务,这对你是隐藏的,这是Task.Factory.StartNew
没有做的 当您将异步委托与
Task.Run
一起使用时,您会创建一个新线程,然后在您点击await Task.Delay
后放弃控制权。延续将 运行 在任意线程池线程上。此外,委托由编译器转换为状态机。使用普通委托,您创建一个线程,同步阻塞它 5 秒,然后从您离开的地方继续。没有国家机器,没有让步。
So, even if it yields with an await on Task.Delay, what is the use in this scenario, since the thread is anyways a isolated thread not used for anything else and even if it just uses Thread.Sleep, the thread would still context switch to yield to other threads for the processor.
当您想同时执行 CPU 和 IO 绑定工作时,可以将 async
与 Task.Run
一起使用,所有这些都在专用线程中进行。您的想法是正确的,在异步委托产生之后,它 returns 在任意线程上。但是,如果您没有使用 Task.Run
,并且 async
方法是从附加了自定义同步上下文(例如 WinformsSynchronizationContext)的线程执行的,那么 await
之后的任何工作都会产生回到 UI 消息循环,除非你使用 ConfigureAwait(false)
.
说实话,Task.Run
和async
正确使用的场景我还没见过多少。但有时它确实有意义。