Announcing the Async CTP for Visual Basic (and also Iterators!)

VBTeam

We’re very happy to announce today the Async CTP for Visual Basic and C#.

Asynchronous programming is something that helps make your UI more responsive, especially in applications that interact with databases or network or disk. It’s also used to make ASP servers scale better. And it’s the natural way to program in Silverlight.

Until now, asynchronous programming has also been prohibitively hard, “not worth the investment”-hard. But with the Async CTP we’ve made asynchronous programming easy enough that developers should routinely consider asynchrony for most of their applications.

Async is a true “parity” feature between VB and C#. We had the same designers develop it in VB and C# at the same time, and the same developers implement the feature for both compilers, and even the same unit tests for both. The end result is a feature that’s keyword-for-keyword identical in both languages (and probably bug-for-bug compatible in the CTP…)

We’re also very happy to announce that iterators are coming to VB, and are included in the Async CTP! That’s because async and iterators are deeply related (and inside the compiler they’re implemented with 99% the same codebase). We’ll write further posts about iterators.

 

A real-world example of asynchrony

“A waiter’s job is to wait on a table until the patrons have finished their meal.
If you want to serve two tables concurrently, you must hire two waiters.”

Q. That sentence is obviously wrong. What is the flaw?

A. You don’t need two waiters! A single waiter can easily serve two tables concurrently, just by switching between them.

Why am I talking about waiters? Think of the waiter as a thread, and the table as a method that it executes. Traditionally, when you wanted to do two things at the same time (e.g. keep the UI responsive while downloading a file) then you’d have used two threads. But it’s inefficient to create extra threads (hire waiters), and you had to jump through hoops to update the UI from the background thread (make sure that the waiters don’t conflict).

 

Let’s see what the waiter really does, written using VB Async:

Async Function WaitOnTablesAsync() As System.Threading.Tasks.Task(Of Decimal)
    Dim takings As Decimal = 0D
    While Not TimeToGoHome
        DeliverMenus()
        Await GetOrdersAsync()
        Await WaitForKitchenAsync()
        GetFoodFromKitchen()
        GiveFoodToPatrons()
        Await WaitForPatronsToFinish()
        takings += Await GetPayment()
    End While
    Return takings
End Function

Async Sub Button1_Click() Handles Button1.Click
    Dim takings As Decimal = Await WaitOnTablesAsync()
    MessageBox.Show(“Shift finished; took {0}”, takings)
End Sub

 

Things to notice in this code:

  1. At each Await keyword, the waiter (thread) suspends execution of the method he’s currently in. He can go off to do other work, like responding to UI events. When the thing he’s awaiting has completed, and he’s free, then he resumes his method.
  2. The WaitOnTablesAsync function has the modifier Async. This modifier allows it to have Await expressions inside.
  3. WaitOnTablesAsync returns a Task(Of Decimal). It actually returns this task promptly at its first Await expression. The task is a placeholder for the work and return value that the waiter will eventually return when he’s finished.
  4. Button1_Click can also Await that Task. Once again, when this task has completed, then Button1_Click can resume and it shows the message-box.

 

What is asynchrony? (and what isn’t it?)

Asynchrony means “not [a-] at the same time [-synchronous]”. It means that the the async function gives back a Task immediately, but that Task is just a placeholder: the real result will be delivered sometime later.

Asynchrony does not mean “running on a background thread”. Running on a background thread is one way to implement asynchrony, but it’s not the only way, and it’s often not the best way.

There are no additional threads in the above code. There’s only a single thread, the UI thread. The Async modifier does not create additional threads. All it does is mark a method as asynchronous (and allow it to Await). If you want to do work on a background thread, you will have to do so explicitly using TaskEx.Run:

Await TaskEx.Run(Sub()
                     ‘ long-running CPU work can go here
                 End Sub)

 

Asynchrony in practice

I read this on a blog recently. It also has a subtle flaw. What is the flaw?

“A good practice in creating responsive applications is to make sure your main UI thread does the minimum amount of work. Any potentially long task that may hang your application should be handled in a different thread. Typical examples of such tasks are network operations, which involve unpredictable delays.”

Hint:

Private Async Sub Button1_Click() Handles Button1.Click
    Dim url = “http://blogs.msdn.com/lucian/rss.aspx”
    Dim wc As New WebClient
    Dim result As String = Await wc.DownloadStringTaskAsync(url)
    Dim rss As XDocument = XDocument.Parse(result)
    MessageBox.Show(rss.DescendantNodes.Count)
End
Sub

 

If you can spot the flaw in the above sentence, or if you can follow this code and understand why it allows the UI to stay responsive, then you’re ready to start coding with the Async CTP!

 

There’s a lot more to read on the subject of asynchrony:

 

0 comments

Leave a comment

Feedback usabilla icon