Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
504 views
in Technique[技术] by (71.8m points)

c# - What difference does it make - running an 'async' action delegate with a Task.Run (vs default action delegate)?

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;
        }));
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...