首页 > 编程语言 >C#知识整理-异步编程

C#知识整理-异步编程

时间:2024-12-30 23:21:06浏览次数:1  
标签:异步 await C# 编程 ConfigureAwait Task 线程 async

.NET 提供了执行异步操作的三种模式:

  • 基于任务的异步模式 (TAP),该模式使用单一方法表示异步操作的开始和完成。TAP 是在 .NET Framework 4 中引入的。这是在 .NET 中进行异步编程的推荐方法。C# 中的async和await关键词以及 Visual Basic 中的Async和Await运算符为 TAP添加了语言支持。
  • 基于事件的异步模式 (EAP),是提供异步行为的基于事件的旧模型。 这种模式需要后缀为Async的方法,以及一个或多个事件、事件处理程序委托类型和EventArg派生类型。 EAP 是在 .NET Framework 2.0 中引入的。 建议新开发中不再使用这种模式。
  • 异步编程模型 (APM) 模式(也称为IAsyncResult模式),这是使用IAsyncResult接口提供异步行为的旧模型。 在这种模式下,同步操作需要Begin和End方法(例如,BeginWrite和EndWrite以实现异步写入操作)。
这里只讨论TAP模式 Task/async/await 关键字: async:接口无法使用async,配合await使用将方法包装为状态机 await:等待一个异步方法完成,可能会来到一个新的线程上 Task:异步任务 async Task/Task: 定义异步方法 async void:无返回值的异步方法,一般async void只有在定义wpf event方法会使用到,async void有一个问题就是无法聚合异常,在调用async void的方法时异常无法捕获可以想见会引发很多问题,所以一般被调用的方法使用async Task 这次的代码使用WPF做案例
//最常见用到的异步调用的,就是Web API的调用
//先定义一个WebAPI
[Route("api/[controller]")]
[ApiController]
public class DemoController : ControllerBase
{
    [HttpGet]
    public string Get()
    {
        return "Test Get API";
    }
}

//在WPF里
//添加3个组件
<Grid>
    <Button Content="GetApiContent" HorizontalAlignment="Center" Margin="0,81,0,0" VerticalAlignment="Top" Click="Button_Click"/>
    <TextBlock Name="text_block" HorizontalAlignment="Center" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Center" Height="192" Width="540"/>
    <TextBox HorizontalAlignment="Left" Margin="143,83,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
</Grid>

//对应的cs文件
private async void Button_Click(object sender, RoutedEventArgs e)
{
        var url = "https://localhost:7163/api/Demo";
        HttpClient client = new HttpClient();
        var result = await client.GetAsync(url).ConfigureAwait(true);
        string content = string.Empty;
        if (result.IsSuccessStatusCode)
        {
            content = await result.Content.ReadAsStringAsync();
        }
    text_block.Text += content;
 
        var getHeavyJobResult = await HeavyJobAsync();
        text_block.Text += getHeavyJobResult;
}
private async Task<int> HeavyJobAsync() {
    await Task.Delay(2000).ConfigureAwait(false);//.ConfigureAwait(true);;
    return 100;
}

  

这段代码还可以这样写
//在同步方法中调用异步方法
          private void Button_Click2(object sender, RoutedEventArgs e)
        {
            var url = "https://localhost:7163/api/Demo";
            HttpClient client = new HttpClient();
            var result = client.GetAsync(url).GetAwaiter().GetResult();
            string content = string.Empty;
            if (result.IsSuccessStatusCode)
            {
                content = result.Content.ReadAsStringAsync().GetAwaiter().GetResult();
            }
            text_block.Text += content;
   //getAwaiter和await一样会释放当前线程
            var getHeavyJobResult = HeavyJobAsync().GetAwaiter().GetResult();
            text_block.Text += getHeavyJobResult;
   
   //不建议使用.Result来写,这里会阻塞线程
            var getHeavyJobResult2 = HeavyJobAsync().Result;                              
            text_block.Text += getHeavyJobResult2;
        }
private async Task<int> HeavyJobAsync() {
//大家可以尝试看看ConfigureAwait(false)和ConfigureAwait(true)
有什么不同
    await Task.Delay(2000).ConfigureAwait(false);//.ConfigureAwait(true);
    return 100;
}

  

ConfigureAwait在WPF中可以避免UI线程上的死锁
  • 如果异步方法在UI线程上启动,并且没有使用ConfigureAwait(false),那么当await操作完成后,它会继续在UI线程上执行,这可能导致死锁,因为UI线程可能正在等待用户输入或其他操作。
  • 使用ConfigureAwait(false)可以避免不必要的上下文切换。
 

标签:异步,await,C#,编程,ConfigureAwait,Task,线程,async
From: https://www.cnblogs.com/terry841119/p/18642683

相关文章

  • C#知识整理-垃圾回收机制(GC)
    垃圾回收的基本知识-.NET|MicrosoftLearn非托管资源CLR系统只能跟踪其生存周期,而不能决定如何释放资源如:数据库连接,文件句柄、指针结果等非托管资源需要手动释放托管资源栈资源托管堆GC主要应用与托管资源从根对象遍历堆上分配的对象,不再被引用到的对象被判定为......
  • ov5640_lcd_display学习笔记
    最近学习了正点原子fpgaov5640摄像头显示例程,特此记录一下。系统框架与接口FPGA要操控的外围器件为ov5640摄像头、LCD和DDR3,接口方面也并不算复杂,用到的接口为sccb、dvp以及RGB888。sccb接口用来配置摄像头寄存器参数,并且iic兼容sccb,所以配置寄存器直接调用iic的驱动模块即......
  • 20. C++快速入门--并发基础
    参考:《Professionalc++》,《并发编程实战》1基本概念1.1竞争原子性"原子"(atomic)操作是指一种不可分割的操作,即在执行过程中不会被中断的操作。这种操作要么完全执行,要么完全不执行,不会出现部分执行的情况。应用场景计数器:在多线程环境下安全地递增或递减计数器。标......
  • 《docker高级篇(大厂进阶):1.Docker复杂安装详说》包括:安装mysql主从复制、安装redis集群
    @目录二、高级篇(大厂进阶)1.Docker复杂安装详说1.1安装mysql主从复制1.2安装redis集群1.2.1面试题:1~2亿条数据需要缓存,请问如何设计这个存储案例哈希取余分区一致性哈希算法分区哈希槽分区1.2.23主3从redis集群扩缩容配置案例架构说明整体流程图知识点总结图使用步骤:注意点说明......
  • 最新版Chrome浏览器集成ActiveX控件步骤
    编写背景   allWebPlugin中间件迎春版刚刚发布,受到很多网友的青睐。它极大的简化了Web系统集成ActiveX插件的步骤,提高了产品的实用性和通用性。本文将详细介绍如何使用allWebPlugin中间件接口,快速集成ActiveX插件。allWebPlugin简介   allWebPlugin中间件是一款......
  • Excel 面试 02 逻辑函数 AND
    Excel中的AND函数用于测试多个条件是否全部为TRUE。如果所有条件都为TRUE,函数返回TRUE;如果有任何一个条件为FALSE,则返回FALSE。语法AND(logical1,[logical2],...)logical1,logical2,…:要测试的逻辑条件,可以是表达式(例如A1>10)、对单元格的引用、或者直接......
  • Flurl.Http集成Microsoft.Extensions.ServiceDiscovery
    .Net8.0及以上版本,微软官方提供了服务发现Nuget包Microsoft.Extensions.ServiceDiscovery,能够对HttpClient请求服务进行服务发现和解析,对于轻量级Flurl.Http来说,也可以进行集成,主要思路是通过HttpClientFactory构建HttpClient实例,调用newFlurlClient(httpClientFactory.Crea......
  • 【Java并发编程线程池】 ForkJoinPool 线程池是什么 怎么工作的 和传统的ThreadPoolEx
    Java中的ForkJoinPool线程池是什么怎么工作的Java中的ForkJoinPool线程池是什么怎么工作的相比较于传统的线程池,ForkJoinPool线程池更适合处理大量的计算密集型任务,它的核心思想是将一个大任务拆分成多个小任务,然后将这些小任务分配给多个线程去执行,最后将这些小任务的......
  • Django Admin 中实现动态表单:无 JavaScript 解决方案
    引言在开发Web应用时,我们经常需要创建动态表单,即根据用户的输入动态更新其他字段的选项。通常,这种功能会使用JavaScript来实现。但是,在某些情况下,我们可能希望避免使用客户端脚本,而完全依赖服务器端逻辑。本文将介绍如何在DjangoAdmin中实现这样的动态表单,而无需使......
  • CSS系列(46)-- Color Functions详解
    前端技术探索系列:CSSColorFunctions详解......