Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

async keyword and choice of the TaskScheduler

I would like to know the reasoning behind the way the compiler choose the TaskScheduler when compiling using the async keyword.

My test method is called by SignalR (ASP.NET host, IIS8, websocket transport) on the OnConnectedAsync method.

protected override async Task OnConnectedAsync(IRequest request, string connectionId)
{
   SendUpdates();
}

Starting a task on the Current synchronization context will result to an InvalidOperationException in System.Web.AspNetSynchronizationContext.OperationStarted()

An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%@ Page Async="true" %>.

Fine. With this SendUpdates definition, I get the above exception:

    private async void SendUpdates()
    {
        Task.Run(async () =>
            {
                while (true)
                {
                    await Task.Delay(1000);
                    await Connection.Broadcast("blabla");
                }
            });

    }

But even more interesting is when I don't get the exception. The following works:

    private void SendUpdates()

And the following works too

    private async Task SendUpdates()

this last one works too, but it's essentially the same as the above example.

    private Task SendUpdates()
    {
        return Task.Run(async () =>
            {
                while (true)
                {
                    await Task.Delay(1000);
                    await Connection.Broadcast("blabla");
                }
            });

    }

Do you know how the compiler choose which scheduler to use here?

like image 943
Eilistraee Avatar asked Oct 23 '12 13:10

Eilistraee


1 Answers

One of the primary guidelines in writing async code is "avoid async void" - that is, use async Task instead of async void unless you're implementing an async event handler.

async void methods use SynchronizationContext's OperationStarted and OperationCompleted; see my MSDN article It's All about the SynchronizationContext for more details.

ASP.NET detects the call to OperationStarted and (correctly) rejects it because it's illegal to put an async event handler there. When you correct the code to use async Task, then ASP.NET no longer sees an async event handler.

You may find my intro to async / await post helpful.

like image 129
Stephen Cleary Avatar answered Oct 30 '22 18:10

Stephen Cleary