Jamie Hartnoll
Jamie Hartnoll

Reputation: 7361

Confusion over Asynchronous code and Await .net

I am sure this question has been asked in many forms before, but I am struggling to find something to clarify my understanding.

As far as I understand it, the concept of asynchronously running certain sections of code in .Net is based around sending work off into multiple threads so that it can run in parallel with other work. In some cases we need to wait for this work to be finished before we can get on with the next thing and in others we don't. I am mainly confused about how to handle these differences.

There are various analogies I can use, but let's look at a builder, or team of builders building a house. At various stages the team are working together on separate tasks, or together on one, here's a very simplified walk-through.

  1. The first task is groundworks. There's nothing to go on, so everyone has to work on digging footings.
  2. We need groundworks to complete before we can do anything else.
  3. Once groundworks are completed We start blockwork and put the walls up.
  4. Now we have walls the electricians and plumbers come in
  5. Their respective tasks are sent off to each trades team and run in parallel to install first-fix wiring and pipe work.
  6. In the meantime, someone has contacted Royal Mail to get this new address added to their postcode/address database.
  7. Plumbers and electricians are done so we can start plasterboarding. ..... etc

In this analogy, we have three types of Task;

I found this question on SO:

How to put this function inside a separate thread

It is quite helpful, mainly the response from "igrimpe", I will copy his code:

Public Class Form1

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

    ' fire and forget:
    Task.Run(Sub() FooA()).ContinueWith(Sub() FooB()).ContinueWith(Sub() FooC())
    Console.WriteLine("Button1 done")

End Sub

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click

    ' fire and forget:
    Task.Run(Sub()
                 FooA()
                 FooB()
                 FooC()
             End Sub)
    Console.WriteLine("Button2 done")

End Sub

Private Async Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click

    ' wait but dont block:
    Await Task.Run(Sub()
                       FooA()
                       FooB()
                       FooC()
                   End Sub)
    Console.WriteLine("Button3 done")

End Sub

Private Sub FooA()
    Threading.Thread.Sleep(1000)
    Console.WriteLine("A")
End Sub

Private Sub FooB()
    Threading.Thread.Sleep(1000)
    Console.WriteLine("B")
End Sub

Private Sub FooC()
    Threading.Thread.Sleep(1000)
    Console.WriteLine("C")
End Sub

End Class

Where he says "fire and forget", I think that is my Postcode analogy, and "wait but don't block" is the Electricians and Plumbers? Am I right that in his example code these jobs will run separately each on their own CPU thread?

Can someone help with code that explicitly outlines the cases I mention above, especially identifying when separate or multiple tasks are finished, either together or individually and ensuring that I understand how to fire tasks to which I do not need a response.

Additionally

This function:

Public Async Sub Report(Message As String)
    Task.Run(Sub() Write(Message)  )
End Sub

Gives me two warnings from Visual Studio: enter image description here and enter image description here

They seem to contradict each other, on the main Sb declaration it is saying this will run synchronously, but where I am declaring a Task it says that because there is no await the method will continue running before the task may be complete - which in this case (fire and forget) I don't care about. Adding Await before run fixes this warning, but I am unclear as to whether this is truly a fire and forget now?

Upvotes: 0

Views: 62

Answers (2)

VeNoMiS
VeNoMiS

Reputation: 330

I'll try to explain the difference between Sync and Async using another analogy.

We need to make a breakfast. Our breakfast is made by these tasks:

  • Cook Eggs (2 min)
  • Make Tea (1 min)
  • Serve (1 min)

Each task can be unattended

Sync approch will be:

  • make Tea and wait (1 min)
  • make Eggs and wait (2 min)
  • Serve Tea and wait (1 min)
  • Serve Eggs and wait (1 min)

Total task time 5 min

Async approch:

  • make Tea
  • make Eggs
  • wait for Tea (1 min)
  • Serve Tea (1 min)
  • (2 min elapsed, Eggs are ready) Serve Eggs (1 min)

Total task time 3 min

If we need to scale the number of breakfasts we can multiply everything by the number of breakfast needed (No concurrency). Or we can increase the number of people working on it (Threads Concurrency)

Upvotes: 2

eistzitrone
eistzitrone

Reputation: 51

I can only answer this question by my C# knowlege :D ... You actually got all of your cases right.

Public Async Sub Report(Message As String)
    Task.Run(Sub() Write(Message)  )
End Sub

This code will do the fire and forget approach. You could just ignore the warning. It is as designed.

I think you could even remove the Async keyword here. You don't want to await for anything here. That could clear the first warning.

If you would change the code like this the execution would be synchronously because you wait until the task has finished it's execution:

Public Async Sub Report(Message As String)
    Await Task.Run(Sub() Write(Message)  )
End Sub

The only difference between calling just Write(Message) without executing it in an awaited task would be that your GUI would stay freezed until the Write function has been finished.

Upvotes: 1

Related Questions