C#学习相关系列之多线程---ConfigureAwait的用法

简介: C#学习相关系列之多线程---ConfigureAwait的用法

一、ConfigureAwait的作用

       ConfigureAwait方法是Task类中的一个实例方法,它用于配置任务的运行上下文。运行上下文指的是任务在执行期间所处的环境,包括线程、同步上下文等。ConfigureAwait方法接受一个布尔值参数,用于决定是否捕获上下文。当参数为true时,表示任务会在之前的上下文中继续执行。当参数为false时,表示任务会在不同的上下文中执行。 ConfigureAwait方法的原理是通过设置Task对象的一个内部状态来实现的。当调用ConfigureAwait方法时,会创建一个新的Task对象,并将原始Task对象的状态复制给该新的Task对象。新的Task对象会在执行时,根据参数值决定是否将上下文捕获。

       通俗的讲,ConfigureAwait可以取决任务之后的代码是继续返回主线程执行还是在新开的线程中继续执行。

二、代码示例

ConfigureAwait在界面中应用最明显:

private void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show($"开始运行,ThreadId:{Thread.CurrentThread.ManagedThreadId}", "button1_Click");
            Test();
            MessageBox.Show($"运行结束,ThreadId:{Thread.CurrentThread.ManagedThreadId}", "button1_Click");
        }
        public static void Test()
         {
             var task = XXXAsync(); // 开启异步任务,比如下载某个资源
             var resuslt = task.Result; // 获取异步任务的结果显示给用户,这里会阻塞当前ui线程直到异步线程返回结果
             MessageBox.Show($"XXXAsync运行结束显示异步任务结果:{resuslt},ThreadId:{Thread.CurrentThread.ManagedThreadId}", "Test");
         }
        private static async Task<string> XXXAsync()
        {
            await Task.Delay(1000);  // 这里会导致死锁
             //await Task.Delay(1000).ConfigureAwait(false); // 这样就不会死锁
 
             MessageBox.Show($"XXXAsync运行结束,ThreadId:{Thread.CurrentThread.ManagedThreadId}", "XXXAsync");
 
             return "XXXAsync.Result";
         }

async /await 出现时var resuslt = task.Result会等待任务执行,直到XXXAsync()有返回结果才会继续执行主线程也就是var resuslt = task.Result在主线程中挂起,一直占用主线程,但await任务后 MessageBox.Show($"XXXAsync运行结束,ThreadId:{Thread.CurrentThread.ManagedThreadId}", "XXXAsync");代码是在同步执行,是在主线程上进行,由于主线程被var resuslt = task.Result一直占用,await代码就会无法在主线程上执行,出现卡死现象。

ConfigureAwait则会解决该问题,当ConfigureAwait(true)时,则是返回主线程执行await后续代码,也是默认情况出现卡死,ConfigureAwait(false)时就会解决该问题,await后的代码会在支线程继续执行,不会出现该问题。

注意: async /await 返回为task与var resuslt = task.Result连用时,await后的任务ConfigureAwait的属性设置为false避免假死。

在非界面代码上进行测试:

static void Main(string[] args)
        {
            Console.WriteLine("开始执行程序");
            Console.WriteLine("这是主函数:{0}", Thread.CurrentThread.ManagedThreadId);
            var task = tt();
            var result = task.Result;
            Console.WriteLine("运行结果为:"+result+"  "+ Thread.CurrentThread.ManagedThreadId);
            Console.Read();
            
        }
        public static async Task<string> tt()
        {
            await Task.Run(() =>
            {
                Console.WriteLine("这是等待方法异步线程:{0}", Thread.CurrentThread.ManagedThreadId);
            }).ConfigureAwait(true);
            Console.WriteLine("这是异步方法剩余内容:{0}", Thread.CurrentThread.ManagedThreadId);
            return "异步方法完成";
        }

await后续代码并没有返回主线程执行,而是直接在支线程执行,并没有出现卡死的情况。猜想或许只有在界面操作时才会出现假死情况!在后续中也会继续留意该问题!


相关文章
|
20天前
|
SQL 开发框架 安全
C#编程与多线程处理
【4月更文挑战第21天】探索C#多线程处理,提升程序性能与响应性。了解C#中的Thread、Task类及Async/Await关键字,掌握线程同步与安全,实践并发计算、网络服务及UI优化。跟随未来发展趋势,利用C#打造高效应用。
|
1月前
|
安全 C#
C# List基本用法
C# List基本用法
|
1月前
|
C#
C# Dev chartControl的用法
C# Dev chartControl的用法
|
2月前
|
存储 缓存 安全
【C/C++ 关键字 存储类说明符 】 线程局部变量的魔法:C++ 中 thread_local的用法
【C/C++ 关键字 存储类说明符 】 线程局部变量的魔法:C++ 中 thread_local的用法
36 0
|
2天前
|
Java API 调度
【Java多线程】Thread类的基本用法
【Java多线程】Thread类的基本用法
6 0
|
3天前
|
安全 Java C#
C#多线程详解
C#多线程详解
12 0
|
12天前
|
消息中间件 缓存 Java
【多线程学习】深入探究定时器的重点和应用场景
【多线程学习】深入探究定时器的重点和应用场景
|
12天前
|
监控 安全 Java
【多线程学习】深入探究阻塞队列与生产者消费者模型和线程池常见面试题
【多线程学习】深入探究阻塞队列与生产者消费者模型和线程池常见面试题
|
12天前
|
消息中间件 监控 安全
【JAVAEE学习】探究Java中多线程的使用和重点及考点
【JAVAEE学习】探究Java中多线程的使用和重点及考点
|
17天前
|
安全 Java API
Java从入门到精通:3.2.1分布式与并发编程——深入Java并发包,精通多线程高级用法
Java从入门到精通:3.2.1分布式与并发编程——深入Java并发包,精通多线程高级用法