在相同代码上使用匿名调用和异步/等待模式时的不同行为,而无需启动ui线程

时间:2018-02-15 23:02:22

标签: c# multithreading asynchronous

我正在使用异步等待进行一些测试,因为我的一个单元测试根本没有返回,除非我要添加一个ConfigureAwait(false);参与其中一项任务。好吧,我决定找出那里到底发生了什么,并编写了以下测试。我不知道为什么,但匿名电话(3.)阻止,而1& 2不要。

我正在尝试检查与ilspy的差异,但我认为就这种行为得到一些意见会很有趣。我正在参加vs 2017 .net 4.5.2。我知道async void很糟糕......这不是重点。

[编辑]我添加了一些更多细节,因此您可以看到开头没有SyncContext,因为这是一个CONSOLE应用程序。此外,很久以前在这里发布了这类问题:https://blog.stephencleary.com/2012/02/async-console-programs.html

internal class Program
{
    private static void Main(string[] args)
    {
        //System.Console.WriteLine($"Main dispatcher: {SynchronizationContext.Current?.GetHashCode()}");
        //// 1. Method call - no blocking
        //var mainTask = Task.Run(() => DoTheSame());
        //mainTask.Wait();

        // 2. Anonymous + Thread - no block
        //var mainThread = new Thread(
        //async () =>
        //{
        //    System.Console.WriteLine($"Before setting dispatcher: {SynchronizationContext.Current?.GetHashCode()}");
        //    SynchronizationContext.SetSynchronizationContext(
        //                    new DispatcherSynchronizationContext(
        //                    Dispatcher.CurrentDispatcher));
        //    System.Console.WriteLine($"After setting dispatcher: {SynchronizationContext.Current?.GetHashCode()}");

        //    var ts = new TaskCompletionSource<bool>();

        //    await Task.Run(() =>
        //    {
        //        ts.SetResult(true);
        //    });

        //    await ts.Task;
        //});
        //mainThread.Start();
        //mainThread.Join();

        // 3. Anonymous + Task - blocks
        var mainTask = Task.Run(
        async () =>
        {
            System.Console.WriteLine($"Before setting dispatcher: {SynchronizationContext.Current?.GetHashCode()}"); // null of course
            SynchronizationContext.SetSynchronizationContext(
                            new DispatcherSynchronizationContext(
                            Dispatcher.CurrentDispatcher));
            System.Console.WriteLine($"After setting dispatcher: {SynchronizationContext.Current?.GetHashCode()}");
            var ts = new TaskCompletionSource<bool>();
            await Task.Run(() =>
            {
                ts.SetResult(true);
            });

            // using .ConfigureAwait(false); will make it work

            await ts.Task;
        });

        mainTask.Wait();
    }

    private static async void DoTheSame()
    {
        System.Console.WriteLine($"Before setting dispatcher: {SynchronizationContext.Current?.GetHashCode()}");
        SynchronizationContext.SetSynchronizationContext(
                        new DispatcherSynchronizationContext(
                        Dispatcher.CurrentDispatcher));
        System.Console.WriteLine($"After setting dispatcher: {SynchronizationContext.Current?.GetHashCode()}");

        var ts = new TaskCompletionSource<bool>();

        await Task.Run(() =>
        {
            ts.SetResult(true);
        });

        await ts.Task;
    }
}

0 个答案:

没有答案