I have this method WaitForReaderArrival
which is like below: (Runs all the time waiting for a reader to arrive)
public void WaitForReaderArrival()
{
do
{
if (ReaderArrived())
{
break;
}
System.Threading.Thread.Sleep(1000);
} while (ReaderArrived() == false);
}
And I am awaiting for the reader to arrive using,
await Task.Run(new Action(WaitForReaderArrival));
if (ReaderArrived())
{
//Raise an ReaderArrived here!
..//blah blah
}
One of my co-worker asked me to change the above line just to
WaitForReaderArrival();
if (ReaderArrived())
{
//Raise an ReaderArrived here!
..//blah blah
}
The question is:
Is the asynchronous model that I adopted above is not really useful? Why she asked me to change that line to normal synchronous methodology is still a question to me.
What in the above is the right way to wait for something to happen and then proceed?
Is the asynchronous model that I adopted above is not really useful?
Why she asked me to change that line to normal synchronous methodology
is still a question to me.
The code you're using is a slightly improved version of the busy waiting loop, which is polling for something with throttling. If you don't have any other ways of getting notified of the change, you can offload this loop to a pool thread as you're doing already with await Task.Run
, or better yet, use Task.Delay
:
public async Task WaitForReaderArrivalAsync()
{
while (!ReaderArrived())
{
await Task.Delay(1000).ConfigureAwait(false);
}
}
One of my co-worker asked me to change the above line... What in the
above is the right way to wait for something to happen and then
proceed?
Your coworker is wrong. If you call your original WaitForReaderArrival
without wrapping it with await Task.Run
, or call the version proposed above as WaitForReaderArrivalAsync().Wait()
, you will block the UI thread. To keep the UI thread message loop functional, you should make your code "Async All the Way":
// top-level event handler
async void Button_Click(object sender, EventArgs e)
{
await WaitForReaderArrivalAsync();
MessageBox.Show("ReaderArrived!");
}
That's the right way of calling it. Conceptually, it is very similar to checking ReaderArrived
upon a timer event, but async/await
gives you convenient linear pseudo-synchronous code flow.
Note, there is a popular anti-pattern which does busy waiting with DoEvents
to keep the UI responsive, effectively creating a nested message loop on the UI thread:
public void WaitForReaderArrival()
{
while (!ReaderArrived())
{
Application.DoEvents();
System.Threading.Thread.Sleep(100);
}
}
Doing so is wrong: Keeping your UI Responsive and the Dangers of Application.DoEvents.
From the viewpoint of your code, there is no difference. Execution will cease at this point and not resume until after the relevant event has occurred.
From the viewpoint of other concurrent activities they could not be more different. In the 'await' case the thread does not block, in the second synchronous case it does. The decision as to which to use depends on other factors which you have not divulged here.
If this is the UI thread, you most likely don't want it to block. Use 'await'.
If this is a dedicated worker thread, you most likely do want it to block. Use the synchronous form.
I must point out that on strict analysis, the second if (ReaderArrived())
is wrong. It should be an assertion, since there is nothing useful to be done otherwise.
Also, consider avoiding 'busy sleep' waiting. It's usually a bad way to do this kind of thing.
Finally, you really must get used to the idea of talking to your co-workers first before coming here. :)
Answer to your second point
Basically I would suggest dont go with above code use the events if your intension is do something on occurence of another event.
What in the above is the right way to wait for something to happen and
then proceed?
You could pass a continuation (a.k.a. callback) to your procedure:
public void WaitForReaderArrival(Action callback)
{
do
{
if ( ReaderArrived() )
{
break;
}
System.Threading.Thread.Sleep(1000);
} while ( ReaderArrived() == false );
callback();
}
Usage example:
WaitForReaderArrival(() =>
{
// Raise an ReaderArrived here!
// ...blah blah
});
Is the asynchronous model that I adopted above is not really useful?
Why she asked me to change that line to normal synchronous methodology
is still a question to me.
The point is that somewhere in your application, you'll have to wait for Reader
to arrive. Even when you do the waiting in another background thread, you'll still have to wait for that thread to finish.
My only concern is that using Thread.Sleep()
on the UI thread will freeze your application. Consider an event-based approach.