async关键字和TaskScheduler的选择

Eil*_*aee 8 c# async-await signalr

我想知道编译器在使用async关键字进行编译时选择TaskScheduler的方式背后的原因.

我的测试方法由OnConnectedAsync方法上的SignalR(ASP.NET主机,IIS8,websocket传输)调用.

protected override async Task OnConnectedAsync(IRequest request, string connectionId)
{
   SendUpdates();
}
Run Code Online (Sandbox Code Playgroud)

在Current同步上下文中启动任务将导致System.Web.AspNetSynchronizationContext.OperationStarted()中的InvalidOperationException

此时无法启动异步操作.异步操作只能在异步处理程序或模块中启动,或者在页面生命周期中的某些事件中启动.如果在执行页面时发生此异常,请确保标记页面<%@ Page Async="true" %>.

精细.使用此SendUpdates定义,我得到以上异常:

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

    }
Run Code Online (Sandbox Code Playgroud)

但更有趣的是,当我没有得到例外.以下作品:

    private void SendUpdates()
Run Code Online (Sandbox Code Playgroud)

以下也有效

    private async Task SendUpdates()
Run Code Online (Sandbox Code Playgroud)

这最后一个也有效,但它与上面的例子基本相同.

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

    }
Run Code Online (Sandbox Code Playgroud)

你知道编译器如何选择在这里使用哪个调度程序吗?

Ste*_*ary 12

编写async代码的主要原则之一是"避免async void" - 也就是说,除非您正在实现事件处理程序async Task,async void否则请使用async.

async void方法使用SynchronizationContextOperationStartedOperationCompleted; 有关详细信息,请参阅我的MSDN文章所有关于SynchronizationContext的内容.

ASP.NET检测到调用OperationStarted和(正确)拒绝它,因为在async那里放置事件处理程序是非法的.当您更正要使用的代码时async Task,ASP.NET不再看到async事件处理程序.

您可能会发现我的介绍async/ await发布有用.