C# TAP异步编程(Task/async/await)总结

C#中有个很好用的东西,TAP异步编程(Task-based Asynchronous Pattern),是目前C#推荐的异步编程模型。它基于 System.Threading.Tasks.Task 和 async/await 关键字,旨在简化异步代码的编写、调试和维护。TAP 是现代 .NET 应用开发中最常用、最推荐的异步编程方式。
要实现TAP,有三个基本元素:Task、async和await。

  • Task: 表示一个异步操作,可能没有返回值(Task)或有返回值(Task<T>
  • async: 标记一个方法为异步
  • await: 用于等待一个异步操作完成,不会阻塞当前线程。

在Winform中,使用好TAP编程,可以方便的将异步回调操作变为同步,且不会阻塞UI线程! 非常优雅。

千问3给出的TAP优势:

特性说明
简化异步代码使用 async/await 避免了复杂的回调嵌套(回调地狱)。
线程友好不会阻塞主线程(如 UI 线程),提升用户体验。
异常处理统一异常可以通过 try/catch 捕获,不需要额外的错误回调。
取消支持支持通过 CancellationToken 安全取消异步操作。
上下文感知通过 SynchronizationContext 自动恢复执行上下文(如 UI 线程)

1.回调封装为异步

回调的关键是需要有key来识别是哪次调用!
通过TaskCompletionSource来封装回调执行时传输的结果数据。
通过await 一个Task实现阻塞等待。
基本代码如下:

public static class CallBackAsync{// 存储异步任务的上下文private static readonly ConcurrentDictionary<int, TaskCompletionSource<int>> _pendingTasks = new ConcurrentDictionary<int, TaskCompletionSource<int>>();// 回调中调用public static void OnCallBackAsync(int key, int result){if (_pendingTasks.TryRemove(key, out var tcs)){tcs.TrySetResult(result);//这里会激发await,并返回结果}}// 异步调用public static async Task<int> ChannelCtrlAsync(int key){var tcs = new TaskCompletionSource<int>();// 缓存任务上下文_pendingTasks[key] = tcs;// 调用原生同步方法int ret = NativeFunc(key);if (ret != 0){_pendingTasks.TryRemove(key, out _);tcs.TrySetException(new Exception($"{ret}")); //通过异常码返回错误!}return await tcs.Task; //关键点}// 原生方法public static int NativeFunc(int key){Console.WriteLine("NativeFunc");//异常情况//return -1;//线程中模拟回调Task.Run(() =>{OnCallBackAsync(1, 99);});return 0;}}

这里用ConcurrentDictionary字典封装了key和TaskCompletionSource的上下文信息,异步调用时要创建一份,回调时进行查找并删除。
注意当原生调用立即返回错误且不进回调时,产生的错误码没法通过TaskCompletionSource传出,此时可通过异常机制来输出。

按钮调用的实现:

private async void button1_Click(object sender, EventArgs e) //必须async标记{try{var result = await CallBackAsync.ChannelCtrlAsync(1).ConfigureAwait(true); // 恢复UI上下文//继续干其他事情,UI不会阻塞}catch (Exception ex){//表示底层调用直接返回了错误码Console.WriteLine($"底层直接返回,返回值:{ex.Message}");}}

2.阻塞调用封装

此时无需TaskCompletionSource去手动等待,比如串口的阻塞式异步:

public async Task SendDataAsync(string strText){return await Task.Run(() =>{m_Port.Write(strText);});}

3.任务取消

通过传入参数CancellationTokenSource 对象,可以在外部调用Cancel()方法取消任务。

public async Task SendXXXAsync(string strText, CancellationTokenSource cts){return await Task.Run(() =>{while(1){if (cts != null && cts.Token.IsCancellationRequested){return;}m_Port.Write(部分数据); //循环发送使用}});}

4.超时处理

var timeoutTask = Task.Delay(TimeSpan.FromSeconds(3));
var completedTask = await Task.WhenAny(task, timeoutTask);
if (completedTask == timeoutTask)
{// 超时处理逻辑tcs.TrySetException(new Exception("ERR_CTRL_TIMEOUT")); //通过异常码返回错误!
}
return await tcs.Task;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/web/83487.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

达梦数据库(DM)用户名大小写处理规则

达梦数据库(DM)用户名大小写处理规则 达梦数据库对用户名的处理与PostgreSQL和Oracle有所不同&#xff0c;以下是相关说明&#xff1a; 一、基本规则 默认情况下&#xff1a;达梦数据库区分用户名大小写 创建的用户名会保留原始大小写格式连接时必须使用相同的大小写形式 …

黑马点评面试话术

文章目录 1.项目介绍2. 分布式登录功能2.1 讲讲登录的整个流程2.2 集群模式session下存储用户信息会有啥问题&#xff1f;2.3 为什么采用redis存储用户信息和验证码2.4 redis的存储格式怎么样的&#xff1f;2.5 为什么采用Hash结构存储用户信息2.6 为什么采用双拦截器&#xff…

MTK APEX测光系统中各变量具体的计算方式探究

目录 一、APEX测光系统介绍 二、MTK测光系统实例介绍 三、关于测光系统的一些疑问 一、APEX测光系统介绍 详细内容可以参考; AE(自动曝光)系统简介

K8S的基本概念

Kubernetes是一个开源的容器编排部署管理平台,用于管理云平台中多个主机上的容器化应用。Kubernetes的目标是让部署容器化的应用简单并且高效,Kubernetes提供了应用部署、规划、更新、维护的一种机制。 对应用开发者而言,可以把Kubernetes看成一个集群操作系统。Kubernetes…

NLP学习路线图(三十四): 命名实体识别(NER)

一、命名实体识别(NER)是什么? 命名实体识别(Named Entity Recognition, NER)是自然语言处理中的一项关键序列标注任务。其核心目标是从非结构化的文本中自动识别出特定类别的名词性短语,并将其归类到预定义的类别中。 核心目标:找到文本中提到的命名实体,并分类。 典…

大三自学笔记:探索Hyperlane框架的心路历程

## Day 1&#xff1a;初识 Hyperlane 在 GitHub 上发现了 Hyperlane 这个 Rust HTTP 框架&#xff0c;立刻被它的性能数据吸引。官方文档写着&#xff1a; > "hyperlane 是一个高性能且轻量级的 Rust HTTP 框架&#xff0c;设计目标是简化现代 Web 服务的开发&#xff…

Java大厂面试真题:谢飞机的技术挑战

Java大厂面试真题&#xff1a;谢飞机的技术挑战 场景一&#xff1a;电商场景 面试官&#xff1a;在电商项目中&#xff0c;我们通常需要处理大量的并发请求。请谈谈你对JVM调优的理解。 谢飞机&#xff1a;嗯&#xff0c;JVM调优主要是为了提高程序的性能和稳定性。比如&…

【Docker管理工具】安装容器管理工具Oxker

【Docker管理工具】安装Oxker容器管理工具 一、Oxker介绍1.1 Oxker简介1.2 Oxker功能1.3 Docker介绍 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载Oxker镜像五、安装Oxke…

产品成本分析怎么做?从0到1搭建全生命周期分析框架!

目录 一、为什么要做产品全生命周期成本分析&#xff1f; 1.资源再分配 2.动态成本校准 3.战略决策支持 二、产品成本分析思路 1.建立全生命周期成本追踪 2.联动分析关键指标 3.定位问题产品线 4.资源效率四象限分配 三、产品成本分析指标 1.分投入成本&#xff1a;…

机器学习与深度学习20-数学优化

目录 前文回顾1.梯度下降的基本原理2.什么是损失函数&#xff1f;3.随机梯度下降和小批量梯度下降4.什么是学习率5.优化算法中的收敛性6.常用的数学优化算法 前文回顾 上一篇文章链接&#xff1a;地址 1.梯度下降的基本原理 梯度下降&#xff08;Gradient Descent&#xff0…

Photoshop 2025 性能配置全攻略:硬件选购与软件优化指南

一、硬件配置核心建议 根据Adobe官方要求及实测反馈&#xff0c;Photoshop 2025对硬件的需求侧重CPU、内存和存储&#xff0c;显卡需求相对宽松&#xff0c;但特定功能&#xff08;如AI滤镜、3D渲染&#xff09;需关注显卡性能。 硬件类别最低配置推荐配置&#xff08;流畅运…

华为云Flexus+DeepSeek征文 | 华为云ModelArts Studio快速上手:DeepSeek-R1-0528商用服务的开通与使用

华为云FlexusDeepSeek征文 | 华为云ModelArts Studio快速上手&#xff1a;DeepSeek-R1-0528商用服务的开通与使用 引言一、ModelArts Studio平台介绍华为云ModelArts Studio简介ModelArts Studio主要特点 二、开通DeepSeek-R1-0528商用服务访问ModelArts Studio控制台DeepSeek-…

day53 神经网络调参指南

目录 一、引言 二、权重初始化&#xff1a;为何如此重要&#xff1f; &#xff08;一&#xff09;随机种子&#xff1a;确保实验的可重复性 &#xff08;二&#xff09;权重初始化的重要性 1. 神经网络的对称性问题 2. 避免梯度消失和梯度爆炸 &#xff08;三&#xff0…

【大模型02---Megatron-LM】

文章目录 Megatron-LM数据并行模型并行张量并行流水线并行 3D并行 Megatron-LM Megatron是当前大模型训练时经常使用的一种分布式并行框架&#xff0c;它通过采用DP,TP,PP等来加速模型的训练&#xff0c;反正就是一个字&#xff0c;好。 大模型在训练的时候&#xff0c;显存占…

魔百和网络机顶盒CM211-1硬件解析

先来个正面照 背面照 核芯 无线网卡 支持WiFi与蓝牙 硬盘 正面内存与背面内存

Kratos 与Golang Cms的关系

Kratos 与 Golang CMS 的关系 Kratos 是 Bilibili 开源的一款轻量级 Go 语言微服务框架,专注于构建高性能、可扩展的后端服务。虽然它本身并不是一个完整的 CMS(内容管理系统),但它可以用于开发 CMS 系统的后端或 API 服务。 我们的目标是提供全面的微服务开发技术。基于…

在vue3+vite中给 Video视频 添加字幕

Video视频 添加字幕 方式一: 使用 track标签template标签中css样式修改方式二:直接读取.vtt文件方式一: 使用 track标签 参考1:https://blog.csdn.net/weixin_42321819/article/details/112442773 参考2:https://blog.csdn.net/foren_whb/article/details/80810552 template标…

UE4手动实现billboard效果让物体始终面向相机正面

一个很简单的需求&#xff0c;但在网上竟然没查到。首先不能用FindLookAtRotation&#xff0c;因为这是用location算的&#xff0c;是让物体朝向相机的方向&#xff0c;而不是朝向相机的正面。区别如下图所示&#xff1a; 然后想用billboard component&#xff0c;不过这个原生…

在阿里云上搭建n8n

0.安装docker 0.1 删除Docker相关源 #删除Docker相关源 sudo rm -f /etc/yum.repos.d/docker*.repo #卸载Docker和相关的软件包 sudo dnf -y remove \ docker-ce \ containerd.io \ docker-ce-rootless-extras \ docker-buildx-plugin \ docker-ce-cli \ docker-compose-plug…

Qt中的OpenGL (4)[纹理]

文章说明 本文是学习OpenGL的笔记,主要参考大神JoeyDeVries的LearnOpenGL第六课《纹理》,并将教程中的代码基于Qt进行实现。 学习目标 掌握纹理基本知识掌握纹理贴图目录结构 |- |-- HelloTextures|--- hello_textures.cpp|--- hello_textures.h|--- main.cpp|--- CMakeLi…