它有什么区别 - 使用 Task.Run 运行“异步"动作委托(与默认动作委托)? [英] What difference does it make - running an 'async' action delegate with a Task.Run (vs default action delegate)?

查看:39
本文介绍了它有什么区别 - 使用 Task.Run 运行“异步"动作委托(与默认动作委托)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试了解 async/await 并认为我确实了解一些关于用法的事情.但仍然不太清楚在如下场景中的实际好处是什么.

看一下Task.Run的用法.第一种方法使用普通委托并使用 Thread.Sleep,但第二种方法使用异步"委托和 Task.Delay.

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

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

//任务线程使用异步委托公共异步任务RetrySendEmail(MailMessage 消息){bool emailSent = false;等待(Task.Run(***异步()*** =>{for (int i = 0; i <3; i++){如果(电子邮件已发送)休息;别的//等待 5 秒再试***等待任务.延迟(5000);***尝试{Smtphost.Send(message);emailSent = true;休息;}catch (Exception e) { emailSent = false;//日志;}}返回电子邮件已发送;}));}//任务线程使用普通委托公共异步任务RetrySendEmail(MailMessage 消息){bool emailSent = false;等待 (Task.Run(***()*** =>{for (int i = 0; i <3; i++){如果(电子邮件已发送)休息;别的//等待 5 秒再试***线程.睡眠(5000);***尝试{Smtphost.Send(message);emailSent = true;休息;}catch (Exception e){ emailSent = false;//日志;}}返回电子邮件已发送;}));}

解决方案

我的问题是:这对这种方法(或它没有)?

一些差异

  1. Task.Run 中使用 async 委托意味着您实际上运行了一个 Task.由于 Task.Run 具有异步意识并为您解开内部任务,这是 Task.Factory.StartNew 没有做的事情莉>
  2. 当您将异步委托与 Task.Run 一起使用时,您将创建一个新线程,然后在您点击 await Task.Delay 后放弃控制权.延续将在任意线程池线程上运行.此外,委托被编译器转换为状态机.

    使用普通委托,您创建一个线程,同步阻塞它 5 秒,然后从您离开的点继续.没有状态机,没有让步.

<小时><块引用>

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

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

说实话,我没见过那么多Task.Runasync正确使用的场景.但有时确实有意义.

I am trying to get my head around async/await and thought I did understand few things about the usage. But still not quite clear what would be the actual benefit in a scenario like below.

Look at the Task.Run usage. The first method uses a normal delegate and uses Thread.Sleep but the second one uses 'async' delegate and Task.Delay.

My question is : how does this make any difference to this method (or it does not) ?

The method itself is an async method. The code is creating a separate thread (via Task.Run) and this thread has nothing else to do other than executing that delegate. 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.

// 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;
        }));
}

解决方案

My question is : how does this make any difference to this method (or it does not) ?

A couple of differences

  1. Using an async delegate inside Task.Run means that you actually run a Task<Task>. This is hidden from you by the fact that Task.Run is async aware and unwraps the inner task for you, something that Task.Factory.StartNew didn't do
  2. When you use an async delegate with Task.Run, you create a new thread, then yield control once you hit await Task.Delay. The continuation will run on an arbitrary thread-pool thread. Additionaly, the delegate is transformed into a state-machine by the compiler.

    With the normal delegate, you create a thread, synchronously block it for 5 seconds, and then continue at the point you left off. No state-machines, no yielding.


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.

The use of async with Task.Run can be when you want to do both CPU and IO bound work, all in a dedicated thread. You're right in thinking that after the async delegate yields, it returns on an arbitrary thread. Though, if you hadn't used Task.Run, and the async method executed from a thread that had a custom synchronization context attached (such as WinformsSynchronizationContext), any work after the await would yield back to the UI message loop, unless you used ConfigureAwait(false).

To tell the truth, I haven't seen that many scenarios where Task.Run and async are used correctly. But it does make sense at times.

这篇关于它有什么区别 - 使用 Task.Run 运行“异步"动作委托(与默认动作委托)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆