C# | 委托 | 事件 | 异步
委托(Delegate)和事件(Event)
在C#和C++中,委托(Delegate)与事件(Event)以及函数对象(Function Object)是实现回调机制或传递行为的重要工具。虽然它们在语法和具体实现上有所不同,但它们的核心思想是相似的:封装可调用的行为,以便可以在不同的上下文中执行。
1. C#中的委托(Delegate)
定义与作用
- 委托是一种类型安全的函数指针,用于封装方法的引用。
- 它允许将方法作为参数传递,或者存储方法以供后续调用。
- 委托可以指向静态方法或实例方法,并且支持多播(Multicast),即一个委托可以同时调用多个方法。
基本语法
// 定义一个委托类型
public delegate void MyDelegate(string message);// 使用委托
public class Program
{public static void Main(){// 创建委托实例并绑定方法MyDelegate del = new MyDelegate(ShowMessage);del("Hello, World!"); // 调用委托}public static void ShowMessage(string message){Console.WriteLine(message);}
}
特点
- 类型安全:委托在编译时检查方法签名是否匹配。
- 多播支持:通过
+=
操作符,可以将多个方法绑定到同一个委托。MyDelegate del = ShowMessage; del += AnotherMethod; del("Hello"); // 会依次调用ShowMessage和AnotherMethod
2. C#中的事件(Event)
定义与作用
- 事件是基于委托的一种特殊机制,通常用于实现发布-订阅模式。
- 它限制了外部对委托的直接调用,只能通过
+=
或-=
来添加或移除事件处理程序。
基本语法
// 定义事件
public class Publisher
{// 声明事件public event EventHandler<MyEventArgs> Notify;public void DoSomething(){// 触发事件Notify?.Invoke(this, new MyEventArgs("Event Triggered"));}
}// 自定义事件参数类
public class MyEventArgs : EventArgs
{public string Message { get; }public MyEventArgs(string message){Message = message;}
}// 订阅事件
public class Subscriber
{public void OnNotify(object sender, MyEventArgs e){Console.WriteLine($"Received: {e.Message}");}
}// 使用示例
public class Program
{public static void Main(){Publisher publisher = new Publisher();Subscriber subscriber = new Subscriber();// 订阅事件publisher.Notify += subscriber.OnNotify;// 触发事件publisher.DoSomething();}
}
特点
- 封装性:事件对外部隐藏了委托的具体实现,只能通过
+=
或-=
操作。 - 松耦合:发布者和订阅者之间没有直接依赖,适合构建模块化的系统。
3. C++中的函数对象(Function Object)
定义与作用
- 函数对象(也称为仿函数,Functor)是一个重载了
operator()
的类或结构体实例。 - 它可以像函数一样被调用,同时具有普通对象的特性(如保存状态)。
基本语法
#include <iostream>
using namespace std;// 定义一个函数对象
class MyFunctor
{
public:void operator()(string message) const{cout << "Message: " << message << endl;}
};int main()
{// 创建函数对象实例MyFunctor functor;// 调用函数对象functor("Hello, World!");return 0;
}
特点
- 灵活性:函数对象可以保存状态,而普通函数不能。
class Counter { private:int count; public:Counter() : count(0) {}void operator()(){cout << "Count: " << ++count << endl;} };int main() {Counter counter;counter(); // 输出 Count: 1counter(); // 输出 Count: 2return 0; }
- 性能优化:在某些情况下,函数对象比函数指针更高效,因为编译器可以对其进行内联优化。
4. 对比总结
特性 | C# 委托 | C# 事件 | C++ 函数对象 |
---|---|---|---|
本质 | 类型安全的函数指针 | 基于委托的发布-订阅机制 | 重载了operator() 的对象 |
用途 | 封装方法引用,支持多播 | 实现事件驱动的通信机制 | 封装行为,支持状态保存 |
类型安全 | 是 | 是 | 是 |
多播支持 | 支持 | 不直接支持 | 不支持 |
状态保存 | 不支持 | 不支持 | 支持 |
使用场景 | 回调、异步编程 | GUI事件、观察者模式 | STL算法、自定义行为封装 |
5. 示例对比:实现简单的回调机制
C# 委托实现
public delegate void Callback(string message);public class Processor
{public Callback OnComplete;public void Process(){// 模拟处理逻辑OnComplete?.Invoke("Processing Complete");}
}public class Program
{public static void Main(){Processor processor = new Processor();processor.OnComplete = message => Console.WriteLine(message);processor.Process(); // 输出 Processing Complete}
}
C++ 函数对象实现
#include <iostream>
#include <functional>
using namespace std;class Processor
{
private:function<void(string)> callback;public:void SetCallback(function<void(string)> cb){callback = cb;}void Process(){if (callback)callback("Processing Complete");}
};int main()
{Processor processor;// 使用Lambda表达式作为函数对象processor.SetCallback([](string message) {cout << message << endl;});processor.Process(); // 输出 Processing Completereturn 0;
}
6. 总结
- C#的委托和事件更适合面向对象的开发,尤其是在事件驱动的场景中(如GUI编程、异步任务)。
- C++的函数对象则更加灵活,尤其在需要保存状态或与STL算法结合使用时表现出色。
- 两者的核心思想都是封装行为,但在具体实现和应用场景上各有侧重。选择哪种方式取决于语言特性和实际需求。
一些简单的示例
委托(Delegate)和事件(Event)是C#中非常强大的机制,尤其是在实现回调、观察者模式、异步编程等场景时。以下是一些实用的例子,展示如何在实际开发中使用委托和事件。
1. 委托的实用例子
1.1 回调函数
假设我们有一个耗时的任务(例如文件下载),我们希望在任务完成时通知调用者。可以使用委托来实现回调。
using System;public delegate void DownloadCompletedHandler(string fileName);public class FileDownloader
{public DownloadCompletedHandler OnDownloadCompleted;public void DownloadFile(string fileName){Console.WriteLine($"Downloading {fileName}...");// 模拟下载过程System.Threading.Thread.Sleep(2000);Console.WriteLine($"{fileName} downloaded.");// 通知任务完成OnDownloadCompleted?.Invoke(fileName);}
}public class Program
{public static void Main(){FileDownloader downloader = new FileDownloader();// 绑定回调方法downloader.OnDownloadCompleted += fileName =>{Console.WriteLine($"Callback: {fileName} is ready to use.");};// 开始下载downloader.DownloadFile("example.txt");}
}
输出:
Downloading example.txt...
example.txt downloaded.
Callback: example.txt is ready to use.
1.2 多播委托
多播委托允许一个委托同时调用多个方法。以下是一个简单的日志记录系统的例子。
using System;public delegate void LogHandler(string message);public class Logger
{public LogHandler Log;public void RecordLog(string message){Console.WriteLine("Logging...");Log?.Invoke(message);}
}public class Program
{public static void Main(){Logger logger = new Logger();// 添加多个日志处理方法logger.Log += ConsoleLogger;logger.Log += FileLogger;// 记录日志logger.RecordLog("System started.");}public static void ConsoleLogger(string message){Console.WriteLine($"[Console] {message}");}public static void FileLogger(string message){// 模拟写入文件Console.WriteLine($"[File] {message}");}
}
输出:
Logging...
[Console] System started.
[File] System started.
2. 事件的实用例子
2.1 发布-订阅模式
事件通常用于实现发布-订阅模式。以下是一个简单的股票价格监控系统的例子。
using System;public class Stock
{// 定义事件public event EventHandler<PriceChangedEventArgs> PriceChanged;private decimal _price;public decimal Price{get => _price;set{if (_price != value){_price = value;// 触发事件PriceChanged?.Invoke(this, new PriceChangedEventArgs(_price));}}}
}// 自定义事件参数类
public class PriceChangedEventArgs : EventArgs
{public decimal NewPrice { get; }public PriceChangedEventArgs(decimal newPrice){NewPrice = newPrice;}
}public class Investor
{public string Name { get; }public Investor(string name){Name = name;}public void OnPriceChanged(object sender, PriceChangedEventArgs e){Console.WriteLine($"{Name} received notification: New price is {e.NewPrice:C}");}
}public class Program
{public static void Main(){Stock stock = new Stock();Investor investor1 = new Investor("Alice");Investor investor2 = new Investor("Bob");// 订阅事件stock.PriceChanged += investor1.OnPriceChanged;stock.PriceChanged += investor2.OnPriceChanged;// 修改股票价格stock.Price = 100.50m;stock.Price = 102.75m;}
}
输出:
Alice received notification: New price is $100.50
Bob received notification: New price is $100.50
Alice received notification: New price is $102.75
Bob received notification: New price is $102.75
2.2 异步事件处理
在某些情况下,事件处理可能需要异步执行。以下是一个简单的例子,模拟用户登录后触发异步通知。
using System;
using System.Threading.Tasks;public class UserLogin
{public event EventHandler<string> LoginSuccessful;public async Task LoginAsync(string username){Console.WriteLine($"Logging in as {username}...");await Task.Delay(2000); // 模拟登录延迟Console.WriteLine($"Login successful for {username}.");// 异步触发事件LoginSuccessful?.Invoke(this, username);}
}public class NotificationService
{public void OnLoginSuccessful(object sender, string username){Console.WriteLine($"Sending welcome email to {username}...");}
}public class Program
{public static async Task Main(){UserLogin userLogin = new UserLogin();NotificationService notifier = new NotificationService();// 订阅事件userLogin.LoginSuccessful += notifier.OnLoginSuccessful;// 模拟用户登录await userLogin.LoginAsync("JohnDoe");}
}
输出:
Logging in as JohnDoe...
Login successful for JohnDoe.
Sending welcome email to JohnDoe...
2.3 使用EventHandler<T>
简化事件定义
C# 提供了泛型EventHandler<T>
,可以简化事件的定义和使用。以下是一个按钮点击事件的例子。
using System;public class Button
{// 使用泛型EventHandler<T>public event EventHandler<ButtonClickEventArgs> Clicked;public void Click(){Console.WriteLine("Button clicked!");Clicked?.Invoke(this, new ButtonClickEventArgs(DateTime.Now));}
}// 自定义事件参数类
public class ButtonClickEventArgs : EventArgs
{public DateTime ClickTime { get; }public ButtonClickEventArgs(DateTime clickTime){ClickTime = clickTime;}
}public class Program
{public static void Main(){Button button = new Button();// 订阅事件button.Clicked += (sender, e) =>{Console.WriteLine($"Button was clicked at {e.ClickTime}");};// 模拟按钮点击button.Click();}
}
输出:
Button clicked!
Button was clicked at 10/10/2023 14:30:00
3. 总结
- 委托适合用于封装方法引用,支持回调和多播。
- 事件基于委托,主要用于实现发布-订阅模式,常见于GUI编程、异步任务和状态变化通知。
- 上述例子涵盖了常见的应用场景,包括回调、日志记录、股票价格监控、异步事件处理和按钮点击事件。
通过这些例子,你可以更好地理解如何在实际项目中使用委托和事件来构建灵活且可扩展的系统。
与异步的结合
委托(Delegate)和事件(Event)与异步编程之间有着紧密的联系,尤其是在现代C#开发中。它们为异步编程提供了灵活且强大的机制,使得开发者能够以清晰、优雅的方式处理异步任务的结果或状态变化。
以下从几个方面详细分析它们之间的联系:
1. 委托与异步编程
1.1 回调机制
在异步编程中,一个常见的需求是:当某个异步操作完成时,通知调用者执行后续逻辑。委托可以作为回调函数的载体,用于封装需要在异步操作完成后执行的代码。
示例:使用委托处理异步任务结果
using System;
using System.Threading.Tasks;public delegate void TaskCompletedHandler(string result);public class AsyncTaskRunner
{public TaskCompletedHandler OnTaskCompleted;public async Task RunAsync(){Console.WriteLine("Starting asynchronous task...");string result = await Task.Delay(2000).ContinueWith(_ => "Task Result");// 异步任务完成后触发回调OnTaskCompleted?.Invoke(result);}
}public class Program
{public static async Task Main(){AsyncTaskRunner runner = new AsyncTaskRunner();// 绑定回调方法runner.OnTaskCompleted += result =>{Console.WriteLine($"Task completed with result: {result}");};// 启动异步任务await runner.RunAsync();}
}
输出:
Starting asynchronous task...
Task completed with result: Task Result
在这个例子中:
OnTaskCompleted
是一个委托,用于定义异步任务完成后的回调逻辑。- 当异步任务完成后,通过调用委托来通知调用者。
1.2 Func 和 Action
C# 提供了内置的泛型委托 Func<T>
和 Action<T>
,它们可以直接用于异步编程中的回调逻辑。
示例:使用 Func
处理异步任务
using System;
using System.Threading.Tasks;public class AsyncCalculator
{public async Task<int> CalculateAsync(Func<int, int, int> operation, int a, int b){Console.WriteLine("Calculating asynchronously...");await Task.Delay(1000); // 模拟耗时计算return operation(a, b);}
}public class Program
{public static async Task Main(){AsyncCalculator calculator = new AsyncCalculator();// 定义异步计算逻辑int result = await calculator.CalculateAsync((x, y) => x + y, 5, 10);Console.WriteLine($"Result: {result}");}
}
输出:
Calculating asynchronously...
Result: 15
在这个例子中:
Func<int, int, int>
是一个委托,表示接受两个整数参数并返回一个整数的方法。- 异步方法
CalculateAsync
使用该委托来封装具体的计算逻辑。
2. 事件与异步编程
2.1 事件驱动的异步通知
事件通常用于实现发布-订阅模式,在异步编程中,它可以用来通知订阅者某个异步操作的状态变化或完成情况。
示例:使用事件通知异步任务完成
using System;
using System.Threading.Tasks;public class AsyncTaskManager
{// 定义事件public event EventHandler<string> TaskCompleted;public async Task ExecuteAsync(){Console.WriteLine("Executing asynchronous task...");await Task.Delay(2000); // 模拟耗时操作// 触发事件TaskCompleted?.Invoke(this, "Task Completed Successfully");}
}public class Program
{public static async Task Main(){AsyncTaskManager manager = new AsyncTaskManager();// 订阅事件manager.TaskCompleted += (sender, message) =>{Console.WriteLine($"Notification: {message}");};// 执行异步任务await manager.ExecuteAsync();}
}
输出:
Executing asynchronous task...
Notification: Task Completed Successfully
在这个例子中:
TaskCompleted
是一个事件,用于通知订阅者异步任务已完成。- 事件的触发点是在异步操作完成后,确保调用者能够及时收到通知。
2.2 异步事件处理
在某些场景下,事件处理本身可能需要异步执行。C# 支持异步事件处理程序,可以通过 async void
或 async Task
方法来实现。
示例:异步事件处理
using System;
using System.Threading.Tasks;public class NotificationService
{public event EventHandler<string> Notify;public async Task SendNotificationAsync(string message){Console.WriteLine("Sending notification...");await Task.Delay(1000); // 模拟异步发送// 触发事件Notify?.Invoke(this, message);}
}public class Program
{public static async Task Main(){NotificationService service = new NotificationService();// 订阅事件service.Notify += async (sender, message) =>{await Task.Delay(500); // 模拟异步处理Console.WriteLine($"Received notification: {message}");};// 发送通知await service.SendNotificationAsync("Hello, World!");}
}
输出:
Sending notification...
Received notification: Hello, World!
在这个例子中:
- 事件处理程序是一个异步方法,使用
async
关键字定义。 - 这种方式适用于需要在事件处理中执行耗时操作的场景。
3. 委托与事件在异步编程中的优势
3.1 解耦
- 委托允许将异步任务的完成逻辑与任务本身解耦。例如,调用者可以自由定义回调逻辑,而无需修改异步方法的实现。
- 事件进一步增强了这种解耦能力,因为它允许多个订阅者独立响应同一个异步操作的结果。
3.2 灵活性
- 委托支持多播(Multicast),可以在异步任务完成后同时调用多个回调方法。
- 事件通过发布-订阅模式,支持动态添加或移除订阅者,非常适合复杂的异步场景。
3.3 可读性
- 使用委托和事件可以让异步代码更加清晰,尤其是当异步操作涉及多个步骤或状态变化时。
4. 实际应用场景
4.1 GUI 编程
在GUI框架(如WPF或WinForms)中,事件常用于处理用户交互(如按钮点击)。这些事件通常是异步触发的,因为用户操作可能发生在任意时刻。
4.2 Web API 调用
在调用远程API时,可以使用委托或事件来处理异步响应。例如:
- 使用委托定义成功或失败的回调逻辑。
- 使用事件通知订阅者API调用的结果。
4.3 数据流处理
在数据流处理(如Rx.NET或SignalR)中,事件常用于实时推送数据更新。这些数据更新通常是异步生成的。
5. 总结
- 委托和事件是异步编程的重要工具,它们通过回调机制和发布-订阅模式,帮助开发者优雅地处理异步任务的结果或状态变化。
- 委托更适合简单的回调场景,而事件则适合复杂的多订阅者场景。
- 在实际开发中,合理使用委托和事件,可以让异步代码更加清晰、灵活且易于维护。
希望这些内容能帮助你更好地理解委托、事件与异步编程之间的关系!
1. 原例子中的同步实现
1.1 文件下载回调(同步)
public class FileDownloader
{public DownloadCompletedHandler OnDownloadCompleted;public void DownloadFile(string fileName){Console.WriteLine($"Downloading {fileName}...");System.Threading.Thread.Sleep(2000); // 同步阻塞OnDownloadCompleted?.Invoke(fileName);}
}
- 问题:使用
Thread.Sleep
模拟下载,会阻塞当前线程。 - 改进:改用
Task.Delay
和async/await
实现异步。
2. 异步版本的改写
2.1 异步文件下载(使用 async/await
)
using System;
using System.Threading.Tasks;public delegate void DownloadCompletedHandler(string fileName);public class FileDownloader
{public DownloadCompletedHandler OnDownloadCompleted;public async Task DownloadFileAsync(string fileName){Console.WriteLine($"Downloading {fileName}...");await Task.Delay(2000); // 异步等待,不阻塞线程Console.WriteLine($"{fileName} downloaded.");OnDownloadCompleted?.Invoke(fileName);}
}public class Program
{public static async Task Main(){FileDownloader downloader = new FileDownloader();downloader.OnDownloadCompleted += fileName =>{Console.WriteLine($"Callback: {fileName} is ready to use.");};await downloader.DownloadFileAsync("example.txt");}
}
输出:
Downloading example.txt...
example.txt downloaded.
Callback: example.txt is ready to use.
2.2 异步股票价格监控
原例子中的 Price
属性是同步的,但可以通过异步事件触发:
using System;
using System.Threading.Tasks;public class Stock
{public event EventHandler<PriceChangedEventArgs> PriceChanged;private decimal _price;public decimal Price{get => _price;set{if (_price != value){_price = value;PriceChanged?.Invoke(this, new PriceChangedEventArgs(_price));}}}// 异步模拟价格变化public async Task SimulatePriceChangeAsync(){for (int i = 0; i < 3; i++){await Task.Delay(1000); // 异步等待Price += 10.5m; // 触发PriceChanged事件}}
}public class Program
{public static async Task Main(){Stock stock = new Stock();stock.PriceChanged += (sender, e) =>{Console.WriteLine($"Price updated to {e.NewPrice:C}");};await stock.SimulatePriceChangeAsync();}
}
输出:
Price updated to $10.50
Price updated to $21.00
Price updated to $31.50
3. 原例子中的潜在异步场景
3.1 事件处理本身是异步的
即使事件触发是同步的,事件处理方法也可以是异步的。例如:
public class NotificationService
{public event EventHandler<string> Notify;public void SendNotification(string message){Console.WriteLine("Sending notification...");Notify?.Invoke(this, message);}
}public class Program
{public static void Main(){NotificationService service = new NotificationService();// 异步事件处理service.Notify += async (sender, message) =>{await Task.Delay(500); // 模拟异步操作Console.WriteLine($"Received: {message}");};service.SendNotification("Hello, World!");Console.ReadLine(); // 防止主线程退出}
}
输出:
Sending notification...
(等待500ms后)
Received: Hello, World!
4. 总结
- 原例子中的委托和事件是同步的,但可以通过以下方式实现异步:
- 使用
async/await
和Task
改写耗时操作。 - 在事件处理方法中使用异步逻辑(
async void
或async Task
)。
- 使用
- 异步的优势:
- 避免阻塞主线程(例如在GUI应用中保持界面响应)。
- 提高资源利用率(例如在服务器端处理高并发请求)。
通过结合委托、事件和异步编程,可以构建高效且可维护的异步系统。
相关文章:
C# | 委托 | 事件 | 异步
委托(Delegate)和事件(Event) 在C#和C中,委托(Delegate)与事件(Event)以及函数对象(Function Object)是实现回调机制或传递行为的重要工具。虽然…...
算法日记33:14届蓝桥C++B冶炼金属(二分答案)
一、题目: 二、题解: 1、思路解析: 1)首先我们可以发现题目的样例数量为( n < 1000 n<1000 n<1000),因此我们可以考虑 O ( n ∗ l o g n ) O(n*log^n) O(n∗logn)时间复杂度的算法 …...
【YOLO V5】目标检测 WSL2 AutoDL VScode SSH
【YOLO V5】目标检测 WSL2 AutoDL VScode SSH 前言整体思路理解向YOLO 目标检测完整流程 环境配置Anaconda 获取 YOLO 代码与预训练模型下载 YOLOv5 代码和预训练模型配置 YOLOV5 工程环境解压 YOLOv5 源代码 并 添加预训练模型调整依赖版本选择对应的 Python 解释器 数据集准备…...
前端基础之ajax
vue-cli配置代理服务器解决跨域问题 我们可以使用一个代理服务器8080,Vue项目8080发送请求向代理服务器8080发送请求,再由在理服务器转发给后端服务器 首先需要在vue.config.js中配置代理服务器 const { defineConfig } require(vue/cli-service) modul…...
vscode离线配置远程服务器
目录 一、前提 二、方法 2.1 查看vscode的commit_id 2.2 下载linux服务器安装包 2.3 安装包上传到远程服务器,并进行文件解压缩 三、常见错误 Failed to set up socket for dynamic port forward to remote port(vscode报错解决方法)-C…...
C语言——string.h下的特殊库函数
string.h下的特殊函数 strtok(分割字符串)strerror(错误码信息)memcpy(拷贝)memmove(拷贝)memset(设置内存)memcmp(比较大小) strtok(分割字符串) char * strtok ( char * str, const char * s…...
烟花燃放安全管控:智能分析网关V4烟火检测技术保障安全
一、方案背景 在中国诸多传统节日的缤纷画卷中,烟花盛放、烧纸祭祀承载着人们的深厚情感。一方面,烟花璀璨,是对节日欢庆氛围的热烈烘托,寄托着大家对美好生活的向往与期许;另一方面,袅袅青烟、点点烛光&a…...
【一个月备战蓝桥算法】递归与递推
字典序 在刷题和计算机科学领域,字典序(Lexicographical order)也称为词典序、字典顺序、字母序,是一种对序列元素进行排序的方式,它模仿了字典中单词的排序规则。下面从不同的数据类型来详细解释字典序: …...
二、Java-封装playwright UI自动化(根据官网执行步骤,首先封装BrowserFactory枚举类及BrowserManager)
前言 查看playwright官网,api文档了解到,playwright的基本步骤: 1、实例化一个playwright 2、启动一个浏览器类型 3、打开一个页面 所以,在封装时需要有一个浏览器工厂类,定义不同的浏览器类型,在配置文…...
java项目之基于ssm的在线视频网站开发(源码+文档)
项目简介 基于ssm的在线视频网站开发实现了以下功能: 该系统的目标用户包括管理员,用户。管理员上传视频,管理视频,查看视频留言,回复视频留言,管理视频收藏信息,管理公告,管理用户…...
观察者模式的C++实现示例
核心思想 观察者模式是一种行为型设计模式,定义了对象之间的一对多依赖关系。当一个对象(称为Subject,主题)的状态发生改变时,所有依赖于它的对象(称为Observer,观察者)都会自动收到…...
c语言中的主要知识点
一、基础语法与结构 程序结构 包含顺序结构、选择结构(if/switch)、循环结构(for/while/do-while)。 程序必须包含且仅有一个main函数作为入口。 数据类型与变量 基本类型:整型(int、long)、浮…...
Pytorch构建LeNet进行MNIST识别 #自用
LeNet是一种经典的卷积神经网络(CNN)结构,由Yann LeCun等人在1998年提出,主要用于手写数字识别(如MNIST数据集)。作为最早的实用化卷积神经网络,LeNet为现代深度学习模型奠定了基础,…...
docker:Dockerfile案例之自定义centos7镜像
1 案例需求 自定义centos7镜像。要求: 默认登录路径为 /usr可以使用vim 2 实施步骤 编写dockerfile脚本 vim centos_dockerfile 内容如下: #定义父镜像 FROM centos:7#定义作者信息 MAINTAINER handsome <handsomehandsome.com># 设置阿里云…...
post get 给后端传参数
post 方式一 : data: params 作为请求体(Request Body)传递: 你已经展示了这种方式,通过data字段直接传递一个对象或数组。这种方式通常用于传递复杂的数据结构。dowmfrom: function (params) { return request({ u…...
Linux 系统不同分类的操作命令区别
Linux 系统有多种发行版,每种发行版都有其独特的操作命令和工具。以下是一些常见的分类及其操作命令的区别: 1. 基于 Red Hat 的发行版 (RHEL, CentOS, Fedora) 1.1 包管理 安装软件包: bash复制 sudo yum install <package> 更新软件包: bash复制 sudo yum update…...
Checkpoint 模型与Stable Diffusion XL(SDXL)模型的区别
Checkpoint 模型与 Stable Diffusion XL(SDXL)模型 在功能、架构和应用场景上有显著区别,以下是主要差异的总结: 1. 基础架构与定位 Checkpoint 模型 是基于 Stable Diffusion 官方基础模型(如 SD 1.4/1.5)…...
软件工程与实践(第4版 新形态) 练习与实践1
软件工程与实践(第4版 新形态) 练习与实践1 1.填空题 (1)程序,文档 (2)系统软件,支撑软件,应用软件 (3)系统方法 (4)软件开发和维护 (5)工程的概念、原理、技术和方法 (6)实现软件的优质高产 (7)软件开发技术和…...
探秘基带算法:从原理到5G时代的通信变革【九】QPSK调制/解调
文章目录 2.8 QPSK 调制 / 解调简介QPSK 发射机的实现与原理QPSK 接收机的实现与原理QPSK 性能仿真QPSK 变体分析 本博客为系列博客,主要讲解各基带算法的原理与应用,包括:viterbi解码、Turbo编解码、Polar编解码、CORDIC算法、CRC校验、FFT/…...
侯捷 C++ 课程学习笔记:深入理解智能指针
文章目录 每日一句正能量一、引言二、智能指针的核心概念(一)std::unique_ptr(二)std::shared_ptr(三)std::weak_ptr 三、学习心得四、实际应用案例五、总结 每日一句正能量 如果说幸福是一个悖论ÿ…...
基于Qwen-VL的手机智能体开发
先上Demo: vl_agent_demo 代码如下: 0 设置工作目录: 你的工作目录需要如下: 其中utils文件夹和qwenvl_agent.py均参考自 GitHub - QwenLM/Qwen2.5-VL: Qwen2.5-VL is the multimodal large language model series developed by …...
系统盘还原成正常U盘
选择格式化,等格式化完毕就完了 点击还原设备的默认值格式化就完了...
Leetcode 103: 二叉树的锯齿形层序遍历
Leetcode 103: 二叉树的锯齿形层序遍历 问题描述: 给定一个二叉树,返回其节点值的锯齿形层序遍历(即第一层从左到右,第二层从右到左,第三层从左到右,依此类推)。 适合面试的解法:广…...
FastGPT 引申:基于 Python 版本实现 Java 版本 RRF
文章目录 FastGPT 引申:基于 Python 版本实现 Java 版本 RRF函数定义使用示例 FastGPT 引申:基于 Python 版本实现 Java 版本 RRF 函数定义 使用 Java 实现 RRF 相关的两个函数:合并结果、过滤结果 import java.util.*;// 搜索结果类型定义…...
C++中的无锁编程
引言 在当今多核处理器普及的时代,并发编程已成为高性能应用程序开发的关键技术。传统的基于锁的同步机制虽然使用简单,但往往会带来性能瓶颈和死锁风险。无锁编程(Lock-Free Programming)作为一种先进的并发编程范式,…...
【全栈开发】---- 一文掌握 Websocket 原理,并用 Django 框架实现
目录 介绍 底层原理 握手环节详解: 收发数据(加密) Django 中配置 channels 1、注册 channels 2、在 settings.py 中添加 asgi_application 3、修改 asgi.py 文件 4、routing 5、consumers 实现 聊天室 介绍 WebSocket是一种先进的通信协议&…...
游戏引擎学习第135天
仓库:https://gitee.com/mrxiao_com/2d_game_3 回顾 game_asset.cpp 的创建 在开发过程中,不使用任何现成的游戏引擎或第三方库,而是直接基于 Windows 进行开发,因为 Windows 目前仍然是游戏的标准平台,因此首先在这个环境中进行…...
国内支持Stable Diffusion模型的平台
国内支持Stable Diffusion模型的平台 截至2025年3月,国内支持SD模型的平台主要包括以下六类,覆盖不同用户需求和技术层级: 一、模型分享与下载平台 Liblib.ai 描述:国内最大SD原创模型社区,提供海量基础模型、Lora…...
扣子(Coze):重构AI时代的工作流革命
文章目录 扣子(Coze):重构AI时代的工作流革命使用Coze:一、工作流的本质:从单点智能到系统智能二、扣子工作流的技术基因三、场景化实践:从知识库到智能员工四、未来图景:AI Agent的进化之路结语…...
alloc、malloc 与 allocator:内存管理三剑客
内存管理是C语言开发者的核心能力,也是系统级编程的基石。 一、内存分配三剑客:malloc/calloc/realloc 1. malloc函数原理 int* arr (int*)malloc(5 * sizeof(int)); // 分配20字节空间(假设int为4字节) 从堆区分配指定字节的连…...
单细胞分析(21)——SCENIC 分析流程(singularity容器版)
SCENIC 分析流程笔记 SCENIC (Single-Cell rEgulatory Network Inference and Clustering) 是一种基于单细胞 RNA 测序数据的调控网络分析方法,主要用于识别调控因子(TFs)及其靶基因(Regulons),并评估这些…...
亚马逊云科技Marketplace(中国区)上架专业服务产品, “云生态连接器”价值凸显
近日,由西云数据运营的亚马逊云科技Marketplace(中国区)正式支持专业服务产品。此次发布将大幅简化企业对云专业服务的采购流程,实现云软件从规划、部署到支持的全生命周期管理,同时也为合作伙伴提供了更多的销售机会。…...
拉普拉斯·隆格·楞次矢量
L − R − L L-R-L L−R−L 矢量的推导 有平方反比有心力: F ⃗ − k r 2 r ^ \vec F-\dfrac{k}{r^2}\hat r F −r2kr^ 显然角动量 L ⃗ r ⃗ p ⃗ \vec L\vec r\times \vec p L r p 守恒。 故 ∣ L ⃗ ∣ Const \begin{vmatrix}\vec L\end{vmatrix}\…...
GStreamer —— 2.3、Windows下Qt加载GStreamer库后运行 - “教程3:动态管道“(附:完整源码)
运行效果(音频) 简介 上一个教程演示了GStreamer 概念。本教程中的管在它设置为 playing 状态之前完全构建。这没关系。如果 我们没有采取进一步的行动,数据会到达 pipeline 的 pipeline 和 pipeline 将生成错误消息并停止。但 我们将采取进一…...
jupyter notebook更改文件存储路径
默认情况打开是这样的 进入cmd或者Anaconda Prompt,输入以下命令 jupyter notebook --generate-config进入该目录 打开该文件,CTRLF 查找c.ServerApp.root_dir 进行修改。 这样就修改好啦!...
基于遗传算法的无人机三维路径规划仿真步骤详解
基于遗传算法的无人机三维路径规划仿真步骤详解 一、问题定义 目标:在三维空间内,寻找从起点到终点的最优路径,需满足: 避障:避开所有障碍物。路径最短:总飞行距离尽可能短。平滑性:转折角度不宜过大,降低机动能耗。输入: 三维地图(含障碍物,如立方体、圆柱体)。起…...
①EtherCAT转Modbus485RTU网关多路同步高速采集无需编程串口服务器
EtherCAT转Modbus485RTU网关多路同步高速采集无需编程串口服务器https://item.taobao.com/item.htm?ftt&id798036415719 型号 1路总线EC网关 MS-A2-1011 2路总线EC网关 MS-A2-1021 4路总线EC网关 MS-A2-1041 EtherCAT 串口网关 EtherCAT 转 RS485 技术规格 …...
Spring Boot WebFlux 中 WebSocket 生命周期解析
Spring Boot WebFlux 中的 WebSocket 提供了一种高效、异步的方式来处理客户端与服务器之间的双向通信。WebSocket 连接的生命周期包括连接建立、消息传输、连接关闭以及资源清理等过程。此外,为了确保 WebSocket 连接的稳定性和可靠性,我们可以加入重试…...
集合论之集合的表示法
目录 1. 说明 2. 常用表示法 2.1 枚举法(Roster Notation) 2.2 构建法(Set-builder notation) 3. 其它表示法 1. 说明 要表示一个集合,可以直接列出其元素,或者提供一种可以唯一地刻画其元素的方当。 2. 常用表示法 2.1 枚举法(Roster Notatio…...
【C语言】值传递与指针传递,以及 `.` 和 `->` 操作详解
在 C 语言中,函数参数的传递机制和结构体成员的访问方式是编程中的核心概念。值传递(pass-by-value)和指针传递(pass-by-pointer)决定了函数如何处理传入的数据,而 . 操作符 和 -> 操作符 则是访问结构体成员的两种主要工具。这两者密切相关,尤其在处理结构体时,它们…...
机器人训练环境isaac gym以及legged_gym项目的配置问题
完整的安装环境教程(强烈推荐):...
DeepSeek 开源周回顾「GitHub 热点速览」
上周,DeepSeek 发布的开源项目用一个词形容就是:榨干性能!由于篇幅有限,这里仅列出项目名称和简介,感兴趣的同学可以前往 DeepSeek 的开源组织页面,深入探索每个项目的精彩之处! 第一天 FlashML…...
冯 • 诺依曼体系结构
文章目录 冯 • 诺依曼体系结构的介绍冯 • 诺依曼体系结构的由来内存是如何提高冯•诺依曼体系结构效率的?为什么程序运行之前必须先加载到内存?从软件层面上再理解冯 • 诺依曼体系结构(QQ聊天的数据流动)一些知识的补充 冯 • …...
软考架构师笔记-存储管理
1.5 存储管理 存储管理 页式存储组织 虚地址 页号 | 页内地址页表 页号 | 块号物理地址 块号 | 页内地址访存两次:访问页表得到物理地址,根据物理地址得到数据就是把用户程序的空间分成若干页,把内存空间分成若干块,块和页的…...
【杂谈】信创电脑华为w515(统信系统)登录锁定及忘记密码处理
华为w515麒麟芯片版,还有非麒麟芯片版本,是一款信创电脑,一般安装的UOS系统。 准备一个空U盘,先下载镜像文件及启动盘制作工具,连接如下: 百度网盘 请输入提取码 http://livecd.uostools.com/img/apps/l…...
C#实现语音合成播报器——基于System.Speech的语音交互方案,在windows上实现语音播报指定文本
——基于System.Speech的语音交互方案,在windows上实现语音播报指定文本 一、语音合成播报应用场景 语音合成播报器广泛应用于以下领域: 工业控制:生产线异常报警、设备状态实时播报(如网页4中的WinCC语音报警插件)…...
【数据库】关系代数
关系代数 一、关系代数的概念二、关系代数的运算2.1 并、差、交2.2 投影、选择2.3 笛卡尔积2.4 连接2.5 重命名2.6 优先级 一、关系代数的概念 关系代数是一种抽象的数据查询语言用对关系的运算来表达查询 运算对象:关系运算符:4类运算结果:…...
点云滤波方法:特点、作用及使用场景
点云滤波是点云数据预处理的重要步骤,目的是去除噪声点、离群点等异常数据,平滑点云或提取特定频段特征,为后续的特征提取、配准、曲面重建、可视化等高阶应用打下良好基础。以下是点云中几种常见滤波方法的特点、作用及使用场景:…...
MWC 2025 | 移远通信大模型解决方案加速落地,引领服务机器人创新变革
随着人工智能、大模型等技术的蓬勃发展,生成式AI应用全面爆发。在此背景下,服务机器人作为大模型技术在端侧落地的关键场景,迎来了前所未有的发展机遇。 作为与用户直接交互的智能设备,服务机器人需要应对复杂场景下的感知、决策和…...
如何下载安装 PyCharm?
李升伟 整理 一、下载 PyCharm 访问官网 打开 PyCharm 官网,点击 "Download" 按钮25。 版本选择: 社区版(Community):免费使用,适合个人学习和基础开发。 专业版(Professional&#…...