C#實(shí)現(xiàn)線程回調(diào)的示例代碼
在 C# 中,線程回調(diào)是一種常見(jiàn)的編程模式,用于在線程完成任務(wù)后執(zhí)行某些操作。通過(guò)使用 Thread 類或其他更高層次的并發(fā)工具(如 Task),可以實(shí)現(xiàn)線程回調(diào)的功能。
回調(diào)機(jī)制
特點(diǎn)
- 直接性:回調(diào)通常是通過(guò)委托(
Delegate)直接調(diào)用的,邏輯簡(jiǎn)單且明確。 - 單一目標(biāo):回調(diào)一般只針對(duì)一個(gè)特定的目標(biāo)方法。
- 輕量級(jí):由于沒(méi)有額外的中間層(如事件訂閱管理),回調(diào)的開(kāi)銷較小。
性能分析
- 調(diào)用開(kāi)銷:回調(diào)本質(zhì)上是一個(gè)方法調(diào)用,性能開(kāi)銷非常低,幾乎等同于普通方法調(diào)用。
- 內(nèi)存分配:通常不會(huì)涉及額外的內(nèi)存分配,除非需要?jiǎng)?chuàng)建閉包或匿名方法。
- 適用場(chǎng)景:
- 單一任務(wù)完成后的通知。
- 不需要解耦調(diào)用方和被調(diào)用方的場(chǎng)景。
性能優(yōu)勢(shì)
- 更快的執(zhí)行速度,因?yàn)闆](méi)有事件訂閱和分發(fā)的開(kāi)銷。
- 更少的內(nèi)存使用,避免了事件管理相關(guān)的額外開(kāi)銷。
事件機(jī)制
特點(diǎn)
- 廣播性:事件可以支持多個(gè)訂閱者(多播委托),適合一對(duì)多的通知場(chǎng)景。
- 解耦性:事件將發(fā)布者和訂閱者解耦,適合復(fù)雜系統(tǒng)中的模塊化設(shè)計(jì)。
- 靈活性:可以通過(guò)動(dòng)態(tài)添加或移除事件處理器來(lái)改變行為。
性能分析
- 調(diào)用開(kāi)銷:
- 如果只有一個(gè)訂閱者,事件的性能與回調(diào)類似。
- 如果有多個(gè)訂閱者,事件需要遍歷所有訂閱者并逐一調(diào)用其處理方法,這會(huì)增加開(kāi)銷。
- 內(nèi)存分配:
- 事件機(jī)制需要維護(hù)訂閱者的列表,可能會(huì)導(dǎo)致額外的內(nèi)存分配。
- 如果訂閱者頻繁地添加或移除,可能會(huì)引發(fā)垃圾回收的壓力。
- 線程安全:
- 在多線程環(huán)境中,事件的訂閱和觸發(fā)可能需要加鎖或其他同步機(jī)制,進(jìn)一步增加開(kāi)銷。
性能劣勢(shì)
- 多播委托的遍歷會(huì)導(dǎo)致性能下降,尤其是在訂閱者數(shù)量較多的情況下。
- 額外的內(nèi)存分配和垃圾回收壓力可能會(huì)影響性能。
性能對(duì)比總結(jié)
| 特性 | 回調(diào) | 事件 |
|---|---|---|
| 調(diào)用開(kāi)銷 | 低(直接調(diào)用方法) | 較高(可能需要遍歷多個(gè)訂閱者) |
| 內(nèi)存分配 | 少(通常無(wú)額外分配) | 較多(需要維護(hù)訂閱者列表) |
| 適用場(chǎng)景 | 單一任務(wù)完成后的通知 | 一對(duì)多的通知,模塊化設(shè)計(jì) |
| 線程安全性 | 簡(jiǎn)單(通常無(wú)需額外同步) | 復(fù)雜(可能需要加鎖) |
| 擴(kuò)展性 | 較差(只能通知單一目標(biāo)) | 較好(支持動(dòng)態(tài)添加/移除訂閱者) |
以下是實(shí)現(xiàn)線程回調(diào)的幾種方法:
使用Thread類和委托
本文介紹了如何在C#中創(chuàng)建和管理線程以實(shí)現(xiàn)并發(fā)執(zhí)行,包括基本步驟、Lambda表達(dá)式簡(jiǎn)化、線程間通信、數(shù)據(jù)共享與同步,以及ApartmentState在多線程和COM交互中的作用。
using System;
using System.Threading;
class Program
{
// 定義一個(gè)委托,用于回調(diào)
public delegate void CallbackDelegate(string message);
static void Main(string[] args)
{
// 創(chuàng)建線程并傳遞回調(diào)方法
Thread thread = new Thread(() => DoWork("線程任務(wù)完成!", Callback));
thread.Start();
Console.WriteLine("主線程繼續(xù)運(yùn)行...");
thread.Join(); // 等待線程完成
}
// 模擬線程執(zhí)行的任務(wù)
static void DoWork(string message, CallbackDelegate callback)
{
Console.WriteLine("線程正在執(zhí)行任務(wù)...");
Thread.Sleep(2000); // 模擬耗時(shí)操作
callback?.Invoke(message); // 調(diào)用回調(diào)函數(shù)
}
// 回調(diào)方法
static void Callback(string message)
{
Console.WriteLine($"回調(diào)執(zhí)行: {message}");
}
}輸出:
主線程繼續(xù)運(yùn)行...
線程正在執(zhí)行任務(wù)...
回調(diào)執(zhí)行: 線程任務(wù)完成!
使用Task和ContinueWith
C# 提供了更高層次的并發(fā)工具 Task,可以通過(guò) ContinueWith 實(shí)現(xiàn)線程回調(diào)。
using System;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
// 創(chuàng)建任務(wù)
Task task = Task.Run(() =>
{
Console.WriteLine("任務(wù)正在執(zhí)行...");
Thread.Sleep(2000); // 模擬耗時(shí)操作
});
// 使用 ContinueWith 實(shí)現(xiàn)回調(diào)
task.ContinueWith(t =>
{
Console.WriteLine("回調(diào)執(zhí)行: 任務(wù)已完成!");
});
Console.WriteLine("主線程繼續(xù)運(yùn)行...");
task.Wait(); // 等待任務(wù)完成
}
}輸出:
主線程繼續(xù)運(yùn)行...
任務(wù)正在執(zhí)行...
回調(diào)執(zhí)行: 任務(wù)已完成!
使用async/await和回調(diào)
結(jié)合 async/await 可以更優(yōu)雅地處理異步操作,并在任務(wù)完成后執(zhí)行回調(diào)。
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("主線程繼續(xù)運(yùn)行...");
// 執(zhí)行異步任務(wù)
await DoWorkAsync();
// 回調(diào)邏輯
Callback();
}
static async Task DoWorkAsync()
{
Console.WriteLine("任務(wù)正在執(zhí)行...");
await Task.Delay(2000); // 模擬耗時(shí)操作
}
static void Callback()
{
Console.WriteLine("回調(diào)執(zhí)行: 任務(wù)已完成!");
}
}輸出:
主線程繼續(xù)運(yùn)行...
任務(wù)正在執(zhí)行...
回調(diào)執(zhí)行: 任務(wù)已完成!
使用事件機(jī)制
通過(guò)定義事件和事件處理器,也可以實(shí)現(xiàn)線程完成后的回調(diào)。
using System;
using System.Threading;
class Program
{
// 定義事件
public static event Action<string> OnTaskCompleted;
static void Main(string[] args)
{
// 訂閱事件
OnTaskCompleted += Callback;
// 啟動(dòng)線程
Thread thread = new Thread(() => DoWork("線程任務(wù)完成!"));
thread.Start();
Console.WriteLine("主線程繼續(xù)運(yùn)行...");
thread.Join(); // 等待線程完成
}
static void DoWork(string message)
{
Console.WriteLine("線程正在執(zhí)行任務(wù)...");
Thread.Sleep(2000); // 模擬耗時(shí)操作
OnTaskCompleted?.Invoke(message); // 觸發(fā)事件
}
static void Callback(string message)
{
Console.WriteLine($"回調(diào)執(zhí)行: {message}");
}
}輸出:
主線程繼續(xù)運(yùn)行...
線程正在執(zhí)行任務(wù)...
回調(diào)執(zhí)行: 線程任務(wù)完成!
總結(jié)
- Thread + 委托:適合簡(jiǎn)單的線程回調(diào)場(chǎng)景。
- Task + ContinueWith:推薦用于現(xiàn)代 C# 應(yīng)用,簡(jiǎn)潔且功能強(qiáng)大。
- async/await:適用于異步編程,代碼更清晰。
- 事件機(jī)制:適合需要解耦的場(chǎng)景,尤其是多個(gè)訂閱者的情況。
選擇合適的方法取決于具體的應(yīng)用場(chǎng)景和需求。
到此這篇關(guān)于C#實(shí)現(xiàn)線程回調(diào)的示例代碼的文章就介紹到這了,更多相關(guān)C# 線程回調(diào)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#循環(huán)與循環(huán)控制的表達(dá)式樹(shù)實(shí)現(xiàn)
這篇文章介紹了C#循環(huán)與循環(huán)控制的表達(dá)式樹(shù)實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-01-01
C#利用原圖和水印圖的重疊簡(jiǎn)單實(shí)現(xiàn)水印的方法
這篇文章主要介紹了C#利用原圖和水印圖的重疊簡(jiǎn)單實(shí)現(xiàn)水印的方法,實(shí)例演示了完整的水印操作類實(shí)現(xiàn)方法,需要的朋友可以參考下2016-04-04
C#實(shí)現(xiàn)可捕獲幾乎所有鍵盤(pán)鼠標(biāo)事件的鉤子類完整實(shí)例
這篇文章主要介紹了C#實(shí)現(xiàn)可捕獲幾乎所有鍵盤(pán)鼠標(biāo)事件的鉤子類,以完整實(shí)例形式分析了C#捕獲鍵盤(pán)鼠標(biāo)事件的鉤子操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2016-06-06
C# 文件下載之?dāng)帱c(diǎn)續(xù)傳實(shí)現(xiàn)代碼
本篇文章主要介紹了C# 文件下載之?dāng)帱c(diǎn)續(xù)傳實(shí)現(xiàn)代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01
C#中調(diào)用SAPI實(shí)現(xiàn)語(yǔ)音識(shí)別的2種方法
這篇文章主要介紹了C#中調(diào)用SAPI實(shí)現(xiàn)語(yǔ)音識(shí)別的2種方法,本文直接給出實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-06-06

