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)是实现回调机制或传递行为的重要工具。虽然…...
android .rc文件
Android .rc 文件的用途 在 Android 系统中,.rc 文件主要是 init 脚本,用于定义和配置 Android 系统的启动过程。.rc 文件的扩展名通常为 .rc,例如 init.rc、init.vendor.rc、init.hardware.rc 等。这些文件是 Android 的 init 进程…...
python-leetcode-零钱兑换 II
518. 零钱兑换 II - 力扣(LeetCode) 这个问题是 完全背包问题 的一个变体,可以使用 动态规划 来解决。我们定义 dp[i] 为凑成金额 i 的硬币组合数。 思路: 定义 DP 数组 设 dp[i] 表示凑成金额 i 的组合数,初始化 dp[…...
Sass 模块化革命:深入解析 @use 语法,打造高效 CSS 架构
文章目录 前言use 用法1. 模块化与命名空间2. use 中 as 语法的使用3. as * 语法的使用4. 私有成员的访问5. use 中with默认值6. use 导入问题总结下一篇预告: 前言 在上一篇中,我们深入探讨了 Sass 中 import 语法的局限性,正是因为这些问题…...
Kotlin中的数字
1、整数类型 Kotlin 提供了一组表示数字的内置类型。 对于整数,有四种不同大小的类型,因此值的范围也不同: 类型大小(比特数)最小值最大值Byte8-128127Short16-3276832767Int32-2,147,483,648 (-231)2,147,483,647 (…...
利用Postman和Apipost进行API测试的实践与优化-动态参数
在实际的开发和测试工作中,完成一个API后对其进行简单的测试是一项至关重要的任务。在测试过程中,确保API返回的数据符合预期,不仅可以提高开发效率,还能帮助我们快速发现可能存在的问题。对于简单的API测试,诸如验证响…...
【前端基础】Day 9 PC端品优购项目
目录 1. 品优购项目规划 1.1 网站制作流程 1.2 品优购项目整体介绍 1.3 学习目的 1.4 开发工具以及技术栈 1.5 项目搭建工作 1.6 网站favicon图标 1.7 网站TDK三大标签SEO优化 2. 品优购首页制作 2.1 常见模块类命名 2.2 快捷导航shortcut制作 2.3 header制作 2.4…...
FFMPEG利用H264+AAC合成TS文件
本次的DEMO是利用FFMPEG框架把H264文件和AAC文件合并成一个TS文件。这个DEMO很重要,因为在后面的推流项目中用到了这方面的技术。所以,大家最好把这个项目好好了解。 下面这个是流程图 从这个图我们能看出来,在main函数中我们主要做了这几步&…...
Linux搭建个人大模型RAG-(ollama+deepseek+anythingLLM)
本文是远程安装ollama deepseek,本地笔记本电脑安装anythingLLM,并上传本地文件作为知识库。 1.安装ollama 安装可以非常简单,一行命令完事。(有没有GPU,都没有关系,自动下载合适的版本) cd 到…...
Docker 学习(二)——基于Registry、Harbor搭建私有仓库
Docker仓库是集中存储和管理Docker镜像的平台,支持镜像的上传、下载、版本管理等功能。 一、Docker仓库分类 1.公有仓库 Docker Hub:官方默认公共仓库,提供超过10万镜像,支持用户上传和管理镜像。 第三方平台:如阿里…...
PHP之变量
在你有别的编程语言的基础下,你想学习PHP,可能要了解的一些关于变量的信息。 PHP中的变量不用指定数据类型,同时必须用$开头。 全局变量 可以在除函数外任意地方访问,如果需要在函数中访问要先获取 $x 111; function tt() {gl…...
centos和ubuntu下安装redis
1,判断环境是否有gcc gcc --version 如果未安装则执行 yum install -y gcc tcl 2,安装包下载,编译安装 cd /usr/local mkdir redis wget https://download.redis.io/releases/redis-4.0.11.tar.gz tar -xvf redis-4.0.11.tar.gz cd redis-4.0.11 编译 m…...
韩国互联网巨头 NAVER 如何借助 StarRocks 实现实时数据洞察
作者: Youngjin Kim Team Leader, NAVER Moweon Lee Data Engineer, NAVER 导读:开源无国界,在“StarRocks 全球用户精选案例”专栏中,我们将介绍韩国互联网巨头 NAVER 的 StarRocks 实践案例。 NAVER 成立于 1999 年࿰…...
K8s 1.27.1 实战系列(二)安装集群并初始化
一、安装 kubeadm、kubelet 和 kubectl(所有节点) 1、配置k8s的yum源地址 cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgchec…...
生命周期总结(uni-app、vue2、vue3生命周期讲解)
一、vue2生命周期 Vue2 的生命周期钩子函数分为 4 个阶段:创建、挂载、更新、销毁。 1. 创建阶段 beforeCreate:实例初始化之后,数据观测和事件配置之前。 created:实例创建完成,数据观测和事件配置已完成,…...
十一、Redis Sentinel(哨兵)—— 高可用架构与配置指南
Redis Sentinel(哨兵)—— 高可用架构与配置指南 在分布式应用中,Redis 主从复制(Master-Slave)虽然能提供读写分离的能力,但它 无法自动故障转移(failover)。如果主节点(Master)发生故障,系统管理员需要手动将某个从节点(Slave)提升为主节点,并重新配置所有从节…...
java8中young gc的垃圾回收器选型,您了解嘛
在 Java 8 的 Young GC(新生代垃圾回收)场景中,对于 ToC的场景,即需要尽可能减少垃圾回收停顿时间以满足业务响应要求的场景,以下几种收集器各有特点,通常 Parnew和 G1 young表现较为出色,下面详…...
C语言学习笔记-初阶(30)深入理解指针2
1. 数组名的理解 在上一个章节我们在使用指针访问数组的内容时,有这样的代码: int arr[10] {1,2,3,4,5,6,7,8,9,10}; int *p &arr[0]; 这里我们使用 &arr[0] 的方式拿到了数组第⼀个元素的地址,但是其实数组名本来就是地址&…...
【Wireshark 02】抓包过滤方法
一、官方教程 Wireshark 官网文档 : Wireshark User’s Guide 二、显示过滤器 2.1、 “数据包列表”窗格的弹出过滤菜单 例如,源ip地址作为过滤选项,右击源ip->prepare as filter-> 选中 点击选中完,显示过滤器&#…...
MySQL基础四(JDBC)
JDBC(重点) 数据库驱动 程序会通过数据库驱动,和数据库打交道。 sun公司为了简化开发人员对数据库的统一操作,提供了一个Java操作数据库的规范。这个规范由具体的厂商去完成。对应开发人员来说,只需要掌握JDBC接口。 熟悉java.sql与javax.s…...
基于CURL命令封装的JAVA通用HTTP工具
文章目录 一、简要概述二、封装过程1. 引入依赖2. 定义脚本执行类 三、单元测试四、其他资源 一、简要概述 在Linux中curl是一个利用URL规则在命令行下工作的文件传输工具,可以说是一款很强大的http命令行工具。它支持文件的上传和下载,是综合传输工具&…...
cenos7网络安全检查
很多网络爱好者都知道,在Windows 2000和Windows 9x的命令提示符下可使用Windows系统自带的多种命令行网络故障检测工具,比如说我们最常用的ping。但大家在具体应用时,可能对这些命令行工具的具体含义,以及命令行后面可以使用的种…...
FastGPT 引申:混合检索完整实例
文章目录 FastGPT 引申:混合检索完整实例1. 各检索方式的初始结果2. RRF合并过程3. 合并后的结果4. Rerank重排序后5. 最终RRF合并6. 内容总结 FastGPT 引申:混合检索完整实例 下边通过一个简单的例子说明不同检索方式的分值变化过程,假设我…...
一、Prometheus架构
Prometheus 云原生十二要素是一套最佳实践和规范,旨在帮助开发人员更好地构建云原生应用 这十二个要素分别是: 单一职责独立部署无状态声明式API服务发现容错处理自适应算法自动化运维响应式编程通信协议服务注册与发现数据持久化一、Prometheus 是什么 Prometheus 是一个…...
蓝桥杯C组真题——巧克力
题目如下 思路 代码及解析如下 谢谢观看...
【大模型】大模型分类
大模型(Large Models)通常指参数量巨大、计算能力强大的机器学习模型,尤其在自然语言处理(NLP)、计算机视觉(CV)等领域表现突出。以下是大模型的常见分类方式: 1. 按应用领域分类 …...
WebUSB的常用API及案例
WebUSB API 允许网页与 USB 设备进行交互,但出于安全考虑,浏览器要求在调用 requestDevice 方法(用于请求用户选择一个 USB 设备并授予网页访问权限)时,必须是在处理用户手势(例如点击按钮)的过…...
在线研讨会 | 加速游戏和AI应用,全面认识Imagination DXTP GPU
近日,Imagination宣布推出 Imagination DXTP GPU IP,该产品重新定义了智能手机和其他功耗受限设备的图形和计算加速。它专为高效的效率而设计,能够提供运行AI、游戏和用户界面体验所需的性能,确保这些体验可以全天候流畅且持续地运…...
The Rust Programming Language 学习 (三)
所有权 所有权(系统)是 Rust 最为与众不同的特性,它让 Rust 无需垃圾回收器(garbage collector)即可保证内存安全。因此,理解 Rust 中所有权的运作方式非常重要。 这里是非常重非常重的一个知识点,这里一…...
【一个月备战蓝桥算法】递归与递推
字典序 在刷题和计算机科学领域,字典序(Lexicographical order)也称为词典序、字典顺序、字母序,是一种对序列元素进行排序的方式,它模仿了字典中单词的排序规则。下面从不同的数据类型来详细解释字典序: …...
