newprint
newprint

Reputation: 7136

Task that has asynchronous IO operation

(I am still in early stage of learning async-await and Task Parallel Library.)
I was asked to add some functionality to our existing project: send out email notification when system gets important data.

// part of API; called by other parts of the program
public override void PrivateSignal(IEventInformation ev) 
{
   // ... some light CPU processing of data

   // will do some IO bound (non-CPU bound) processing
   // in my case, send out email notification 
   // using `System.Net.Mail.SmtpClient`class
  smptClient.SendMail(CaptureRC.SmptFromEmailAddr, 
                                 ToEmails, CaptureRC.EmailSubject,   
                             "seen moving" + tag.ToString());
}

According to answers to my previous questions and blog post by Stephen Cleary, following construct is not a good choice to make my code "asynchronous":

public override void PrivateSignal(IEventInformation ev) {
    Task.Run(async ()=>{await smptClient.SendMailAsync(....);}).Wait();
}

Assume for the moment that PrivateSignal() was called 50 times in a row, and I would make IO operation synchronous:

public override void PrivateSignal(IEventInformation ev) {
        Task.Run(()=>{ smptClient.SendMail(....);}).WaitAll();
    }

This will create 50 threads in the pool, and each one of them will be blocked by synchronous call, in addition, .WaitAll()will block running thread (I can get rid of .WaitAll() since return from SendMail() is void). Overall, 51 threads stuck, doing nothing.

What could be possible be done to improve IO operation without wasting so much time and resources ?

Upvotes: 0

Views: 206

Answers (2)

Stephen Cleary
Stephen Cleary

Reputation: 456507

What could be possible be done to improve IO operation without wasting so much time and resources?

The best answer is to make PrivateSignal asynchronous, just like the accepted answer to your last question suggested. Yes, this does mean that the base class has to change, and all the methods that call PrivateSignal have to change. They have to change in order to enable asynchrony.

If you don't want to change PrivateSignal, then PrivateSignal is forced to be synchronous. And that forces you to use SendMail, which blocks the thread. Because that's what synchronous means.

In order to be asynchronous, you must change PrivateSignal so that it can be asynchronous.

(Side note in interest of full disclosure: it is possible to declare PrivateSignal as an async void method. However, this raises a whole host of problems. For details, see the "avoid async void" section of my MSDN article on async best practices or do a search on that phrase.)

Upvotes: 2

Remus Rusanu
Remus Rusanu

Reputation: 294287

Consider using an async SMTP client, like SmtpClient.SendAsync:

Sends the specified e-mail message to an SMTP server for delivery. This method does not block the calling thread

Upvotes: 1

Related Questions