【C#】线程回调

在 C# 中,线程回调是一种常见的编程模式,用于在线程完成任务后执行某些操作。通过使用 Thread 类或其他更高层次的并发工具(如 Task),可以实现线程回调的功能。

回调机制

特点

  • 直接性:回调通常是通过委托(Delegate)直接调用的,逻辑简单且明确。
  • 单一目标:回调一般只针对一个特定的目标方法。
  • 轻量级:由于没有额外的中间层(如事件订阅管理),回调的开销较小。

性能分析

  • 调用开销:回调本质上是一个方法调用,性能开销非常低,几乎等同于普通方法调用。
  • 内存分配:通常不会涉及额外的内存分配,除非需要创建闭包或匿名方法。
  • 适用场景
    • 单一任务完成后的通知。
    • 不需要解耦调用方和被调用方的场景。

性能优势

  • 更快的执行速度,因为没有事件订阅和分发的开销。
  • 更少的内存使用,避免了事件管理相关的额外开销。

 

 事件机制

特点

  • 广播性:事件可以支持多个订阅者(多播委托),适合一对多的通知场景。
  • 解耦性:事件将发布者和订阅者解耦,适合复杂系统中的模块化设计。
  • 灵活性:可以通过动态添加或移除事件处理器来改变行为。

性能分析

  • 调用开销
    • 如果只有一个订阅者,事件的性能与回调类似。
    • 如果有多个订阅者,事件需要遍历所有订阅者并逐一调用其处理方法,这会增加开销。
  • 内存分配
    • 事件机制需要维护订阅者的列表,可能会导致额外的内存分配。
    • 如果订阅者频繁地添加或移除,可能会引发垃圾回收的压力。
  • 线程安全
    • 在多线程环境中,事件的订阅和触发可能需要加锁或其他同步机制,进一步增加开销。

性能劣势

  • 多播委托的遍历会导致性能下降,尤其是在订阅者数量较多的情况下。
  • 额外的内存分配和垃圾回收压力可能会影响性能。

 性能对比总结

特性回调事件
调用开销低(直接调用方法)较高(可能需要遍历多个订阅者)
内存分配少(通常无额外分配)较多(需要维护订阅者列表)
适用场景单一任务完成后的通知一对多的通知,模块化设计
线程安全性简单(通常无需额外同步)复杂(可能需要加锁)
扩展性较差(只能通知单一目标)较好(支持动态添加/移除订阅者)

 

以下是实现线程回调的几种方法:

使用 Thread 类和委托

【C#】Thread的使用-CSDN博客文章浏览阅读1.5k次,点赞10次,收藏26次。本文介绍了如何在C#中创建和管理线程以实现并发执行,包括基本步骤、Lambda表达式简化、线程间通信、数据共享与同步,以及ApartmentState在多线程和COM交互中的作用。 https://blog.csdn.net/wangnaisheng/article/details/136051621?spm=1011.2415.3001.5331

using System;
using System.Threading;class Program
{// 定义一个委托,用于回调public delegate void CallbackDelegate(string message);static void Main(string[] args){// 创建线程并传递回调方法Thread thread = new Thread(() => DoWork("线程任务完成!", Callback));thread.Start();Console.WriteLine("主线程继续运行...");thread.Join(); // 等待线程完成}// 模拟线程执行的任务static void DoWork(string message, CallbackDelegate callback){Console.WriteLine("线程正在执行任务...");Thread.Sleep(2000); // 模拟耗时操作callback?.Invoke(message); // 调用回调函数}// 回调方法static void Callback(string message){Console.WriteLine($"回调执行: {message}");}
}

输出:

主线程继续运行...
线程正在执行任务...
回调执行: 线程任务完成!

使用 Task 和 ContinueWith

C#中Task类的异步编程详解:基础用法与实践-CSDN博客文章浏览阅读1.8k次,点赞13次,收藏10次。C# Task的使用_c# task用法 https://blog.csdn.net/wangnaisheng/article/details/136036934?spm=1011.2415.3001.5331C# 提供了更高层次的并发工具 Task,可以通过 ContinueWith 实现线程回调。

using System;
using System.Threading.Tasks;class Program
{static void Main(string[] args){// 创建任务Task task = Task.Run(() =>{Console.WriteLine("任务正在执行...");Thread.Sleep(2000); // 模拟耗时操作});// 使用 ContinueWith 实现回调task.ContinueWith(t =>{Console.WriteLine("回调执行: 任务已完成!");});Console.WriteLine("主线程继续运行...");task.Wait(); // 等待任务完成}
}

输出:

主线程继续运行...
任务正在执行...
回调执行: 任务已完成!

使用 async/await 和回调

C# async/await的使用_c# async await用法-CSDN博客文章浏览阅读1.3k次,点赞5次,收藏8次。本文详细介绍了C#中async和await关键字在实现异步编程中的作用,包括如何定义异步方法、await用于等待异步操作完成的特点,以及注意事项,如避免阻塞操作和正确嵌套。这些技术有助于提升程序性能和响应性。 https://blog.csdn.net/wangnaisheng/article/details/136037585?spm=1011.2415.3001.5331结合 async/await 可以更优雅地处理异步操作,并在任务完成后执行回调。

using System;
using System.Threading.Tasks;class Program
{static async Task Main(string[] args){Console.WriteLine("主线程继续运行...");// 执行异步任务await DoWorkAsync();// 回调逻辑Callback();}static async Task DoWorkAsync(){Console.WriteLine("任务正在执行...");await Task.Delay(2000); // 模拟耗时操作}static void Callback(){Console.WriteLine("回调执行: 任务已完成!");}
}

输出: 

主线程继续运行...
任务正在执行...
回调执行: 任务已完成!

使用事件机制

通过定义事件和事件处理器,也可以实现线程完成后的回调。

using System;
using System.Threading;class Program
{// 定义事件public static event Action<string> OnTaskCompleted;static void Main(string[] args){// 订阅事件OnTaskCompleted += Callback;// 启动线程Thread thread = new Thread(() => DoWork("线程任务完成!"));thread.Start();Console.WriteLine("主线程继续运行...");thread.Join(); // 等待线程完成}static void DoWork(string message){Console.WriteLine("线程正在执行任务...");Thread.Sleep(2000); // 模拟耗时操作OnTaskCompleted?.Invoke(message); // 触发事件}static void Callback(string message){Console.WriteLine($"回调执行: {message}");}
}

输出:

主线程继续运行...
线程正在执行任务...
回调执行: 线程任务完成!

总结

  • Thread + 委托:适合简单的线程回调场景。
  • Task + ContinueWith:推荐用于现代 C# 应用,简洁且功能强大。
  • async/await:适用于异步编程,代码更清晰。
  • 事件机制:适合需要解耦的场景,尤其是多个订阅者的情况。

选择合适的方法取决于具体的应用场景和需求。

 

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

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

相关文章

【C++游戏引擎开发】第14篇:视图空间与相机坐标系

一、视图空间的基础数学框架 1.1 齐次坐标与变换矩阵 三维坐标系变换采用44齐次坐标矩阵,其通用形式为: M = [ A 3 3 b 3 1 0 1 3 1 ] \mathbf{M} = \begin{bmatrix} \mathbf{A}_{33} & \mathbf{b}_{31} \\ \mathbf{0}_{13} & 1 \end{bmatrix} M=[A33​013​​…

【大模型理论篇】关于生成式模型中联合分布概率学习必要性以及GPT是生成式模型的讨论

1. 背景 之前我们在《生成式模型与判别式模型对比(涉及VAE、CRF的数学原理详述)》以及《生成式模型算法原理深入浅出&#xff08;涉及Stable Diffusion、生成对抗网络、高斯混合模型、隐马尔可夫模型、朴素贝叶斯等算法原理分析及生成式模型解释&#xff09;》中&#xff0c;我…

DIP支付方式改革下各种疾病医疗费用的影响以及分析方法研究综述

DIP支付方式改革下各种疾病医疗费用的影响以及分析方法研究综述 摘要 本文综述了DIP支付方式改革对不同疾病医疗费用的影响及其分析方法&#xff0c;通过分析12篇相关文献&#xff0c;探讨了DIP支付方式在控制医疗费用、优化费用结构、提升医疗服务效率等方面的作用及其局限性…

嵌入式硬件篇---单片机周期

文章目录 前言 前言 在单片机中&#xff0c;时序控制是其执行指令和协调外设的核心基础。以下是单片机中常见的各种周期及其详细说明&#xff0c;以层次结构展开&#xff1a; 时钟周期&#xff08;Clock Cycle&#xff09; 定义&#xff1a; 时钟周期是单片机的最小时间单位&a…

游戏引擎学习第221天:(实现多层次过场动画)

资产: intro_art.hha 已发布 在下载页面&#xff0c;你会看到一个新的艺术包。你将需要这个艺术包来进行接下来的开发工作。这个艺术包是由一位艺术家精心制作并打包成我们设计的格式&#xff0c;旨在将这些艺术资源直接应用到游戏中。它包含了许多我们会在接下来的直播中使用…

【3GPP核心网】【5G】精讲5G系统的策略和计费控制框架

1. 欢迎大家订阅和关注,精讲3GPP通信协议(2G/3G/4G/5G/IMS)知识点,专栏会持续更新中.....敬请期待! 目录 1. 系统架构 1.1 非漫游架构 1.2 漫游架构 1.3 支持Rx接口 2. 服务化接口及参考点 2.1 PCF 与 AF 间接口 2.2 PCF与SMF间接口 2.3 PCF与AMF间接口 2.4 V-PC…

榕壹云门店管理系统:基于Spring Boot+Mysql+UniApp的智慧解决方案

项目背景&#xff1a;数字化赋能服务行业&#xff0c;破解传统门店管理痛点 在消费升级与数字化转型浪潮下&#xff0c;传统服务行业&#xff08;如美容、美发、美甲、采耳等&#xff09;面临诸多管理挑战&#xff1a;会员流失率高、预约排班混乱、员工绩效统计低效、数据孤岛等…

开发效率提升200%——cursor

cursor带来的编程"革命" 高级语言编程转为"自然语言编程"借助cursor&#xff0c;直接超越初级后台开发、超越初级前端开发、超越初级测试、超越初级UI&#xff0c;产研一体linux命令只用学不用记&#xff0c;语言描述就是命令给一个表结构流程提示词&…

UE4 踩坑记录

1、Using git status to determine working set for adaptive non-unity build 我删除了一个没用的资源&#xff0c;结果就报这个错&#xff0c;原因就是这条命令导致的&#xff0c; 如果这个项目是git项目&#xff0c; ue编译时会优先通过 git status检查哪些文件被修改&#…

蓝桥杯 2025 C++组 省 B 题解

可分解的正整数 算法&#xff1a;思维 因为可以有负数 所以除了1以外的任何数都可以构造 当这个数为x构造方法为 -(x-1) -(x-2) -(x-3) ....-1 0 1...x-3 x-2 x-1 x 除了x&#xff0c;x以前的数都会被负数抵消 #include <bits/stdc.h> #define ll long long ll a…

docker创建容器添加启动--restart选项

一、通过 Docker 命令直接修改已启动的容器&#xff08;推荐-已验证&#xff09; 操作步骤&#xff1a; 1.执行更新命令&#xff1a; docker update --restartalways <容器名或ID>此命令会将容器的重启策略调整为 always&#xff08;无论容器以何种状态退出&#xff0…

redission锁释放失败处理

redission锁释放失败处理 https://www.jianshu.com/p/055ae798547a 就是可以删除 锁的key 这样锁就释放了&#xff0c;但是 还是要结合业务&#xff0c;这种是 非正规的处理方式&#xff0c;还是要在代码层面进行处理。

【语音识别】vLLM 部署 Whisper 语音识别模型指南

目录 1. 模型下载 2. 环境安装 3. 部署脚本 4. 服务测试 语音识别技术在现代人工智能应用中扮演着重要角色&#xff0c;OpenAI开源的Whisper模型以其出色的识别准确率和多语言支持能力成为当前最先进的语音识别解决方案之一。本文将详细介绍如何使用vLLM&#xff08;一个高…

Windows Server 2019 安装 Docker 完整指南

博主本人使用的是离线安装 1. 安装前准备 系统要求 操作系统&#xff1a;Windows Server 2019&#xff08;或 2016/2022&#xff09;权限&#xff1a;管理员权限的 PowerShell网络&#xff1a;可访问互联网&#xff08;或离线安装包&#xff09; 启用容器功能 Install-Win…

C# 混淆代码工具--ConfuserEx功能与使用指南

目录 1 前言1.1 可能带来的问题 2 ConfuserEx2.1 简介2.2 功能特点2.3 基本使用方法2.4 集成到MSBuild2.5 深入设置2.5.1 保护机制2.5.1.1 ConfuserEx Protection 2.5.2 精细的代码保护主要特性1. decl-type(string)2.full-name(string)3. is-public()4. match(string)5. match…

c# 新建不重名的唯一文件夹

在源文件夹内创建唯一目标文件夹 string newFolder GetUniqueFolderName(sourceFolder); Directory.CreateDirectory(newFolder); /// <summary>/// 生成唯一文件夹名称&#xff08;格式&#xff1a;新建文件夹、新建文件夹1、新建文件夹2...&#xff09;…

3D案例丨多个3D工业相机拼接检测 开启360°新视界

在高速生产线上&#xff0c;经常需要在极短的时间内对工件进行全方位的外观检测&#xff0c;如&#xff1a;线缆直径和直线度检测、锂电池外观缺陷检测、铁轨截面尺寸检测等。 这需要传感器完整还原被测物的截面面轮廓形状&#xff0c;并获取精准的截面轮廓数据。但单一相机的…

openapi + knife4j的使用

一、依赖作用与关系 1. springdoc-openapi-starter-webmvc-api • 核心功能&#xff1a; 基于 OpenAPI 3 规范&#xff0c;自动生成 API 文档元数据&#xff08;JSON 格式&#xff09;&#xff0c;并集成 Spring MVC。 提供Tag Operation、Schema 等注解&#xff0c;支持通过…

解决电脑问题——突然断网!

电脑如果突然断网是怎么回事 电脑突然断网可能由多种原因造成&#xff0c;以下是常见的因素&#xff1a; 网络连接与权限问题 路由器或调制解调器故障&#xff1a;路由器或调制解调器可能出现硬件故障、软件故障或设置错误。可以尝试重启设备&#xff0c;如果问题依旧&#…

区块链从专家到小白

文章目录 含义应用场景典型特征 含义 以非对称加密算法为基础。 每个**区块&#xff08;Block&#xff09;**包含&#xff1a; ​交易数据​&#xff08;如转账记录、合约内容&#xff09;。 ​时间戳​&#xff08;记录生成时间&#xff09;。 ​哈希值​&#xff08;当前区…