• ## 使用C# 6.0中的async/await


    异步函数是TPL之上更高级别的抽象,真正简化了异步编程,它与普通函数不一样在于必须有async标识,并且返回类型一般是Task<T>,Task类型,当然也可以使用async void,但更推荐使用async Task,使用async void唯一合理的地方在于程序中使用顶层UI控制器事件处理器的时候。

    异步函数内部,必须至少有一个await操作符,该操作符一般与TPL一起工作,并获取该任务中的异步操作的结果。需要注意的是在执行完await调用的代码行后该方法会立即返回,剩下的异步函数的部分独立异步运行,值得注意的是如果程序中有两个连续的await操作符,它们是顺序运行的,即第一个完成后,第二个才会开始运行。

    await关键字简化了连续性的附着(Simplify the attaching of continuations)。

    比如:

    var result=await expression;
    statement(s);
    

    等价于:

    var awaiter=expression.GetAwaiter();
    awaiter.OnCompleted(()=>{
        var result=awaiter.GetResult();
        statement(s);
    });
    

    可以用以下demo佐证:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace ThreadDemo
    {
        class Program21
        {
            static async Task<string> GetInfoAsync(string name,int seconds)
            {
                //await Task.Delay(TimeSpan.FromSeconds(seconds));
                await Task.Run(() => { 
                    Thread.Sleep(TimeSpan.FromSeconds(seconds));
                    Console.WriteLine($"{name} first :{Thread.CurrentThread.ManagedThreadId}");
                });
                await Task.Run(() => {
                    Thread.Sleep(TimeSpan.FromSeconds(seconds));
                    Console.WriteLine($"{name} second:{Thread.CurrentThread.ManagedThreadId}");
                });
                return $"Task {name} is running on a thread id " +
                    $"{Thread.CurrentThread.ManagedThreadId}. " +
                    $"Is thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}";
            }
            static async Task AsyncProcess()
            {
                Task<string> t1 = GetInfoAsync("Task 1", 3);
                Task<string> t2 = GetInfoAsync("Task 2", 5);
                string[] results = await Task.WhenAll(t1, t2);
                foreach(string result in results)
                {
                    Console.WriteLine(result);
                }
            }
            static void Main()
            {
                Task t = AsyncProcess();
                t.Wait();
            }
        }
    }
    
    

    output:

    Task 1 first :3
    Task 2 first :4
    Task 1 second:5
    Task 2 second:3
    Task Task 1 is running on a thread id 5. Is thread pool thread:True
    Task Task 2 is running on a thread id 3. Is thread pool thread:True
    

    这也说明了为什么上述GetInfoAsync返回的是Task<string>类型,因为await关键字后的任务后面的statement,实际上就是在最后一个await的任务的线程里完成的,所以return $"Task {name} is running on a thread id " + $"{Thread.CurrentThread.ManagedThreadId}. " + $"Is thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}";自然是异步中返回string的函数,即是Task<string>类型。

    await最大的优势在于可以出现在异步函数中的任意地方(除了lock,unsafe环境)。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Threading;
    namespace ThreadDemo
    {
        class Program22
        {
            static async Task<string> GetInoAsync(string name,int seconds)
            {
                Console.WriteLine($"GetInfoAsync Pre:{Thread.CurrentThread.ManagedThreadId}");
                await Task.Delay(TimeSpan.FromSeconds(seconds));
                Console.WriteLine($"GetInfoAsync After:{Thread.CurrentThread.ManagedThreadId}");
                //throw new Exception($"Boom from {name}!");
                return $"In {Thread.CurrentThread.ManagedThreadId}";
            }
            static async Task AsyncProcess()
            {
                Console.WriteLine("1. Single exception");
                try
                {
                    Console.WriteLine($"AsyncProcess Pre:{Thread.CurrentThread.ManagedThreadId}");
                    string result = await GetInoAsync("Task 1", 2);
                    Console.WriteLine(result);
                    Console.WriteLine($"AsyncProcess after:{Thread.CurrentThread.ManagedThreadId}");
                }
                catch(Exception ex)
                {
                    Console.WriteLine($"Exception details:{ex}");
                }
            }
            static void Main()
            {
                Console.WriteLine($"Main ID:{Thread.CurrentThread.ManagedThreadId}");
                Task t = AsyncProcess();
                t.Wait();
            }
        }
    }
    
    

    output:

    Main ID:1
    1. Single exception
    AsyncProcess Pre:1
    GetInfoAsync Pre:1
    GetInfoAsync After:4
    In 4
    AsyncProcess after:4
    

    上面的demo,清楚的显示了线程随着await的变化。

    使用await操作符获取异步任务结果

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Threading;
    namespace ThreadDemo
    {
        class Program17
        {
            static async Task<string> GetInfoAsync(string name)
            {
                await Task.Delay(TimeSpan.FromSeconds(2));
                return $"Task {name} is running on a thread id {Thread.CurrentThread.ManagedThreadId}" +
                    $" Is thread pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
            }
    
            static Task AsynchronyWithTPL()
            {
                Task<string> t = GetInfoAsync("Task 1");
                Task t2 = t.ContinueWith(task => Console.WriteLine(t.Result), TaskContinuationOptions.NotOnFaulted);
                Task t3 = t.ContinueWith(task => Console.WriteLine(t.Exception.InnerException), TaskContinuationOptions.OnlyOnFaulted);
                return Task.WhenAny(t2, t3);
            }
            static async Task AsynchronyWithAwait()
            {
                try
                {
                    string result = await GetInfoAsync("Task 2");
                    Console.WriteLine(result);
                }
                catch(Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
            static void Main()
            {
                Task t = AsynchronyWithTPL();
                t.Wait();
    
                t = AsynchronyWithAwait();
                t.Wait();
            }
        }
    }
    
    

    outputt:

    Task Task 1 is running on a thread id 4 Is thread pool thread: True
    Task Task 2 is running on a thread id 6 Is thread pool thread: True
    

    如果将Task<String> GetInfoAsync函数改为:

            static async Task<string> GetInfoAsync(string name)
            {
                await Task.Delay(TimeSpan.FromSeconds(2));
                //return $"Task {name} is running on a thread id {Thread.CurrentThread.ManagedThreadId}" +
                //    $" Is thread pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
                throw new Exception("Boom!");
            }
    

    output:

    System.Exception: Boom!
       在 ThreadDemo.Program17.<GetInfoAsync>d__0.MoveNext() 位置 E:\LearningCSharp\ThreadTestNetFramework\ThreadDemo\Program17.cs:行号 16
    System.Exception: Boom!
       在 ThreadDemo.Program17.<GetInfoAsync>d__0.MoveNext() 位置 E:\LearningCSharp\ThreadTestNetFramework\ThreadDemo\Program17.cs:行号 16
    --- 引发异常的上一位置中堆栈跟踪的末尾 ---
       在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
       在 ThreadDemo.Program17.<AsynchronyWithAwait>d__2.MoveNext() 位置 E:\LearningCSharp\ThreadTestNetFramework\ThreadDemo\Program17.cs:行号 30
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Threading;
    namespace ThreadDemo
    {
        class Program17
        {
            static async Task<string> GetInfoAsync(string name)
            {
                await Task.Run(() => { Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} is running.."); });
                await Task.Delay(TimeSpan.FromSeconds(2));
                return $"Task {name} is running on a thread id {Thread.CurrentThread.ManagedThreadId}" +
                    $" Is thread pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
                //throw new Exception("Boom!");
            }
    
            static Task AsynchronyWithTPL()
            {
                Task<string> t = GetInfoAsync("Task 1");
                Task t2 = t.ContinueWith(task => Console.WriteLine(t.Result), TaskContinuationOptions.NotOnFaulted);
                Task t3 = t.ContinueWith(task => Console.WriteLine(t.Exception.InnerException), TaskContinuationOptions.OnlyOnFaulted);
                return Task.WhenAny(t2, t3);
            }
            static async Task AsynchronyWithAwait()
            {
                try
                {
                    string result = await GetInfoAsync("Task 2");
                    Console.WriteLine(result);
                }
                catch(Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
            static void Main()
            {
                Task t = AsynchronyWithTPL();
                t.Wait();
    
                t = AsynchronyWithAwait();
                t.Wait();
            }
        }
    }
    
    

    output:

    3 is running..
    Task Task 1 is running on a thread id 4 Is thread pool thread: True
    3 is running..
    Task Task 2 is running on a thread id 6 Is thread pool thread: True
    

    可以发现同一个异步函数内部,不同的await后的任务处理确实是在不同的线程池。

    在lambda表达式中使用await操作符

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Threading;
    namespace ThreadDemo
    {
        class program18
        {
            static async Task AsynchronousProcessing()
            {
                Func<string, Task<string>> asyncLambda = async name =>
                   {
                       await Task.Delay(TimeSpan.FromSeconds(2));
                       return $"Task {name} is running on a thread id {Thread.CurrentThread.ManagedThreadId}." +
                       $" Is thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}";
                   };
                string result = await asyncLambda("async lambda");
                Console.WriteLine(result);
            }
            static void Main()
            {
                Task t = AsynchronousProcessing();
                t.Wait();
            }
        }
    }
    
    

    output:

    Task async lambda is running on a thread id 4. Is thread pool thread:True
    

    对连续的异步任务使用await操作符

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Threading;
    namespace ThreadDemo
    {
        class program19
        {
            static async Task<string> GetInfoAsync(string name)
            {
                Console.WriteLine($"Task {name} started!");
                await Task.Delay(TimeSpan.FromSeconds(2));
                if(name=="TPL 2")
                {
                    throw new Exception("Boom!");
                }
                return $"Task {name} is running on a thread id {Thread.CurrentThread.ManagedThreadId}." +
                    $" Is thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}";
            }
    
            static async Task AsyncronyWithAwait()
            {
                try
                {
                    string result = await GetInfoAsync("Async 1");
                    Console.WriteLine(result);
                    result = await GetInfoAsync("Async 2");
                    Console.WriteLine(result);
                }
                catch(Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
    
            static void Main()
            {
                Task t = AsyncronyWithAwait();
                t.Wait();
            }
        }
    }
    
    

    output:

    Task Async 1 started!
    Task Async 1 is running on a thread id 4. Is thread pool thread:True
    Task Async 2 started!
    Task Async 2 is running on a thread id 4. Is thread pool thread:True
    

    对并行执行的异步任务使用await操作符

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace ThreadDemo
    {
        class Program21
        {
            static async Task<string> GetInfoAsync(string name,int seconds)
            {
                await Task.Delay(TimeSpan.FromSeconds(seconds));
                //await Task.Run(() => Thread.Sleep(TimeSpan.FromSeconds(seconds)));
                return $"Task {name} is running on a thread id " +
                    $"{Thread.CurrentThread.ManagedThreadId}. " +
                    $"Is thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}";
            }
            static async Task AsyncProcess()
            {
                Task<string> t1 = GetInfoAsync("Task 1", 3);
                Task<string> t2 = GetInfoAsync("Task 2", 5);
                string[] results = await Task.WhenAll(t1, t2);
                foreach(string result in results)
                {
                    Console.WriteLine(result);
                }
            }
            static void Main()
            {
                Task t = AsyncProcess();
                t.Wait();
            }
        }
    }
    
    

    output:

    Task Task 1 is running on a thread id 4. Is thread pool thread:True
    Task Task 2 is running on a thread id 4. Is thread pool thread:True
    

    我们使用了Task.WhenAll辅助方法创建了另一个任务,该任务的返回类型是Task<string[]>,该任务只有在所有底层任务完成后才会运行。5s后,我们可以观察到,一瞬间全部出来了结果,这说明了这个任务在t1,t2都结束后,才执行。

    但这里也观察到一个非常有趣的现象:并行任务是被线程池同一个工作者线程执行的,How can it be?

    为了搞清楚这个问题,我们需要知道Task.Delay的工作机理是怎么样的!

    它是使用类似这样的技术实现的:

    Task Delay(int milliseconds)
    {
       var tcs=new TaskCompletionSource<object>();
        var timer=new System.Timers.Timer(milliseconds){AutoReset=false};//保证只调用一次
        timer.Elapsed+=delegate{timer.Dispose();tcs.SetResult(null);};
        timer.Start();
        return tcs.Task;
    }
    

    由此可见,对于GetInfoAsync异步方法,当timer所在的线程A达到milliseconds后,坍缩,由于await关键字,线程A将继续执行return 语句,然后A结束,重新回到线程池,当t2再运行时,那么就很有可能重新从线程池中拾取到线程A,结果就造成了t1,t2都用了同一个worker thread。

    如果使用await Task.Run(() => { Thread.Sleep(TimeSpan.FromSeconds(seconds)); 就肯定不会出现以上重复使用同一个worker thread的情况。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace ThreadDemo
    {
        class Program21
        {
            static async Task<string> GetInfoAsync(string name,int seconds)
            {
                //await Task.Delay(TimeSpan.FromSeconds(seconds));
                await Task.Run(() => { 
                    Thread.Sleep(TimeSpan.FromSeconds(seconds));
                    Console.WriteLine($"{name} first :{Thread.CurrentThread.ManagedThreadId}");
                });
                await Task.Run(() => {
                    Thread.Sleep(TimeSpan.FromSeconds(seconds));
                    Console.WriteLine($"{name} second:{Thread.CurrentThread.ManagedThreadId}");
                });
                return $"Task {name} is running on a thread id " +
                    $"{Thread.CurrentThread.ManagedThreadId}. " +
                    $"Is thread pool thread:{Thread.CurrentThread.IsThreadPoolThread}";
            }
            static async Task AsyncProcess()
            {
                Task<string> t1 = GetInfoAsync("Task 1", 3);
                Task<string> t2 = GetInfoAsync("Task 2", 5);
                string[] results = await Task.WhenAll(t1, t2);
                foreach(string result in results)
                {
                    Console.WriteLine(result);
                }
            }
            static void Main()
            {
                Task t = AsyncProcess();
                t.Wait();
            }
        }
    }
    
    

    output:

    Task 1 first :3
    Task 2 first :4
    Task 1 second:5
    Task 2 second:3
    Task Task 1 is running on a thread id 5. Is thread pool thread:True
    Task Task 2 is running on a thread id 3. Is thread pool thread:True
    

    处理异步操作中的异常

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Threading;
    namespace ThreadDemo
    {
        class Program22
        {
            static async Task<string> GetInoAsync(string name,int seconds)
            {
                Console.WriteLine($"GetInfoAsync Pre:{Thread.CurrentThread.ManagedThreadId}");
                await Task.Delay(TimeSpan.FromSeconds(seconds));
                Console.WriteLine($"GetInfoAsync After:{Thread.CurrentThread.ManagedThreadId}");
                throw new Exception($"Boom from {name}!");
                //return $"In {Thread.CurrentThread.ManagedThreadId}";
            }
            static async Task AsyncProcess()
            {
                Console.WriteLine("1. Single exception");
                try
                {
                    Console.WriteLine($"AsyncProcess Pre:{Thread.CurrentThread.ManagedThreadId}");
                    string result = await GetInoAsync("Task 1", 2);
                    Console.WriteLine(result);
                    Console.WriteLine($"AsyncProcess after:{Thread.CurrentThread.ManagedThreadId}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Exception details:{ex}");
                }
                Console.WriteLine();
                Console.WriteLine("2. Multiple exception");
                Console.WriteLine($"Multiple exception Pre:{Thread.CurrentThread.ManagedThreadId}");
                Task<string> t1 = GetInoAsync("Task 1", 3);
                Task<string> t2 = GetInoAsync("Task 2", 2);
                Console.WriteLine($"Multiple await Pre:{Thread.CurrentThread.ManagedThreadId}");
                try
                {
                    string[] results = await Task.WhenAll(t1, t2);
                    Console.WriteLine(results.Length);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Exception details:{ex}");
                }
    
                Console.WriteLine();
                Console.WriteLine("3. Multiple exceptions witth AggregateExceptioon");
                t1 = GetInoAsync("Task 1", 3);
                t2 = GetInoAsync("Task 2", 2);
                Task<string[]> t3 = Task.WhenAll(t1, t2);
                try
                {
                    string[] results = await t3;
                    Console.WriteLine(results.Length);
                }
                catch
                {
                    var ae = t3.Exception.Flatten();
                    var exceptions = ae.InnerExceptions;
                    Console.WriteLine($"Exceptions caught:{exceptions.Count}");
                    foreach (var e in exceptions)
                    {
                        Console.WriteLine($"Exception details:{e}");
                        Console.WriteLine();
                    }
                }
                Console.WriteLine();
                Console.WriteLine("4.await in catch and finally blocks");
                try
                {
                    string result = await GetInoAsync("Task 1", 2);
                    Console.WriteLine(result);
                }
                catch(Exception ex)
                {
                    await Task.Delay(TimeSpan.FromSeconds(1));
                    Console.WriteLine($"Catch block with await:Exceptioon details:{ex}");
                }
                finally
                {
                    await Task.Delay(TimeSpan.FromSeconds(1));
                    Console.WriteLine("Finally block");
                }
            }
            static void Main()
            {
                Console.WriteLine($"Main ID:{Thread.CurrentThread.ManagedThreadId}");
                Task t = AsyncProcess();
                t.Wait();
            }
        }
    }
    
    

    output:

    Main ID:1
    1. Single exception
    AsyncProcess Pre:1
    GetInfoAsync Pre:1
    GetInfoAsync After:4
    Exception details:System.Exception: Boom from Task 1!
       在 ThreadDemo.Program22.<GetInoAsync>d__0.MoveNext() 位置 E:\LearningCSharp\ThreadTestNetFramework\ThreadDemo\Program22.cs:行号 16
    --- 引发异常的上一位置中堆栈跟踪的末尾 ---
       在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
       在 ThreadDemo.Program22.<AsyncProcess>d__1.MoveNext() 位置 E:\LearningCSharp\ThreadTestNetFramework\ThreadDemo\Program22.cs:行号 25
    
    2. Multiple exception
    Multiple exception Pre:4
    GetInfoAsync Pre:4
    GetInfoAsync Pre:4
    Multiple await Pre:4
    GetInfoAsync After:4
    GetInfoAsync After:5
    Exception details:System.Exception: Boom from Task 1!
       在 ThreadDemo.Program22.<GetInoAsync>d__0.MoveNext() 位置 E:\LearningCSharp\ThreadTestNetFramework\ThreadDemo\Program22.cs:行号 16
    --- 引发异常的上一位置中堆栈跟踪的末尾 ---
       在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
       在 ThreadDemo.Program22.<AsyncProcess>d__1.MoveNext() 位置 E:\LearningCSharp\ThreadTestNetFramework\ThreadDemo\Program22.cs:行号 41
    
    3. Multiple exceptions witth AggregateExceptioon
    GetInfoAsync Pre:5
    GetInfoAsync Pre:5
    GetInfoAsync After:4
    GetInfoAsync After:5
    Exceptions caught:2
    Exception details:System.Exception: Boom from Task 1!
       在 ThreadDemo.Program22.<GetInoAsync>d__0.MoveNext() 位置 E:\LearningCSharp\ThreadTestNetFramework\ThreadDemo\Program22.cs:行号 16
    --- 引发异常的上一位置中堆栈跟踪的末尾 ---
       在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
       在 ThreadDemo.Program22.<AsyncProcess>d__1.MoveNext() 位置 E:\LearningCSharp\ThreadTestNetFramework\ThreadDemo\Program22.cs:行号 56
    
    Exception details:System.Exception: Boom from Task 2!
       在 ThreadDemo.Program22.<GetInoAsync>d__0.MoveNext() 位置 E:\LearningCSharp\ThreadTestNetFramework\ThreadDemo\Program22.cs:行号 16
    
    
    4.await in catch and finally blocks
    GetInfoAsync Pre:5
    GetInfoAsync After:4
    Catch block with await:Exceptioon details:System.Exception: Boom from Task 1!
       在 ThreadDemo.Program22.<GetInoAsync>d__0.MoveNext() 位置 E:\LearningCSharp\ThreadTestNetFramework\ThreadDemo\Program22.cs:行号 16
    --- 引发异常的上一位置中堆栈跟踪的末尾 ---
       在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
       在 ThreadDemo.Program22.<AsyncProcess>d__1.MoveNext() 位置 E:\LearningCSharp\ThreadTestNetFramework\ThreadDemo\Program22.cs:行号 74
    Finally block
    

    一个常见的错误就是,对一个以上的异步操作使用await时还使用以上方式。但如果仍像第一种情况一样使用catch代码块,则只能从底层的AggregatetException对象中得到第一个异常,正如第二种情况表现的那样。

    为了收集所有异常信息,**可以使用await任务的Exception属性,第三种情况,使用了AggreagateExceptionFlatten方法将层次异常放入一个列表,并从中提取出所有的底层异常。

    避免使用捕获的同步上下文

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    namespace ThreadDemo
    {
        class Program23
        {
            private static Label _label;
            static async void Click(object sender,EventArgs e)
            {
                _label.Content = new TextBlock() { Text = "Calculating..." };
                TimeSpan resultWithContext = await Test();
                TimeSpan resultNoContext = await TestNoContext();
                //TimeSpan resultNoContext = await TestNoContext().ConfigureAwait(false);
                StringBuilder sb = new StringBuilder();
                sb.AppendLine($"With the context:{resultWithContext}");
                sb.AppendLine($"Without the context:{resultNoContext}");
                sb.AppendLine("Ratio:" +
                    $"{resultWithContext.TotalMilliseconds / resultNoContext.TotalMilliseconds:0.00}");
                _label.Content = new TextBlock() { Text = sb.ToString() };
            }
            [STAThread]
            static void Main()
            {
                Console.WriteLine($"Main Thread ID:{Thread.CurrentThread.ManagedThreadId}");
                Application app = new Application();
                Window win = new Window();
                StackPanel panel = new StackPanel();
                Button button = new Button();
                _label = new Label();
                _label.FontSize = 32;
                _label.Height = 200;
                button.Height = 200;
                button.FontSize = 32;
                button.Content = new TextBlock() { Text = "Start async operations" };
                button.Click += Click;
                panel.Children.Add(_label);
                panel.Children.Add(button);
                win.Content = panel;
                app.Run(win);
                Console.ReadLine();
            }
            static async Task<TimeSpan> Test()
            {
                const int iterationsNumber = 100000;
                var sw = new Stopwatch();
                sw.Start();
                for(int i = 0; i < iterationsNumber; i++)
                {
                    var t = Task.Run(() =>{ });
                    await t;
                }
                sw.Stop();
                return sw.Elapsed;
            }
            static async Task<TimeSpan> TestNoContext()
            {
                const int iterationsNumber = 100000;
                Stopwatch sw = new Stopwatch();
                sw.Start();
                for(int i = 0; i < iterationsNumber; i++)
                {
                    Task t = Task.Run(() => { });
                    await t.ConfigureAwait(continueOnCapturedContext: false);
                }
                sw.Stop();
                return sw.Elapsed;
            }
        }
    }
    
    

    可以看到常规的await操作符花费了更多的时间来完成,这是因为向UI线程中放入了成百上千个后续操作任务,这会使用它的消息循环来异步地执行这些任务,在本例中,我们无需再UI线程中运行该代码,因为异步操作并未访问UI组件

    ....未完待续

  • 相关阅读:
    RabbitMq的死信队列和延迟队列
    Rabbitmq的过期时间
    技术干货 | 源码解析 Github 上 14.1k Star 的 RocketMQ
    深入分析 Flutter 渲染性能
    重磅发布 阿里云数据中台全新产品DataTrust聚焦企业数据安全保障
    DataWorks搬站方案:Airflow作业迁移至DataWorks
    DataWorks搬站方案:Azkaban作业迁移至DataWorks
    基于 Flutter 的 Web 渲染引擎「北海」正式开源!
    走完线上 BUG 定位最后一公里
    10种编程语言实现Y组合子
  • 原文地址:https://www.cnblogs.com/johnyang/p/15983172.html
Copyright © 2020-2023  润新知