Asynchronous Programming
27.1 Why Async?
I/O-bound work (HTTP, DB, file) waits without blocking threads, so UIs stay responsive and servers scale.
CPU-bound work: offload with Task.Run (in UI apps) or parallelize (Module 29).
27.2 Core Syntax
Async Function... As Task / Task(Of T) Event handlers only
Asynchronously wait. The continuation resumes on the captured context (UI thread).
Task.WhenAll / WhenAny Task.Delay, Task.Run, Task.FromResult, Task.CompletedTask Don't capture the context (libraries)
CancellationToken / CancellationTokenSource IProgress(Of T) / Progress(Of T) Report progress to the UI TaskCompletionSource(Of T) Wrap callback/event APIs as tasks ValueTask(Of T) Allocation-free fast paths (consume)
Public Async Function GetOrderSummaryAsync(id As Integer, ct As Threading.CancellationToken) As Task(Of OrderSummary)
Dim orderTask = _orderRepo.GetAsync(id, ct)
Dim customerTask = _customerApi.GetForOrderAsync(id, ct)
Await Task.WhenAll(orderTask, customerTask) ' run concurrently
Return New OrderSummary(orderTask.Result, customerTask.Result) ' safe: tasks already completed
End Function27.3 Wrapping Event-Based APIs
Public Function WaitForExitAsync(p As Process) As Task
Dim tcs As New TaskCompletionSource(Of Boolean)(TaskCreationOptions.RunContinuationsAsynchronously)
p.EnableRaisingEvents = True
AddHandler p.Exited, Sub(s, e) tcs.TrySetResult(True)
If p.HasExited Then tcs.TrySetResult(True)
Return tcs.Task
End Function27.4 Async Pitfalls
❌ .Result / .Wait() on UI or legacy ASP.NET threads → deadlock. Go async all the way.
❌ Async Sub outside event handlers → unobserved exceptions crash the process.
❌ Forgetting Await (fire-and-forget) → lost exceptions. If it's intentional, handle errors explicitly.
❌ Capturing the UI context in libraries → use ConfigureAwait(False).
✅ Pass CancellationToken everywhere. Use timeouts (cts.CancelAfter). Don't block in Sub Main except at the bridge (GetAwaiter().GetResult()).
VB limitations: no Await inside Catch/Finally blocks (as of VB 16.9: you can't await in Catch/Finally), no Await For Each, no Await Using. Restructure code (set a flag in Catch, then await after the Try block).