解鎖C++異步編程:告別阻塞,擁抱高效
你在使用辦公軟件處理文檔時(shí),點(diǎn)擊保存后,軟件界面突然定格,只能眼巴巴地看著進(jìn)度條緩慢前進(jìn),期間什么操作都做不了,是不是很惱人?這便是傳統(tǒng)同步編程的阻塞問題在作祟。同步編程就像單行道,任務(wù)得一個(gè)接一個(gè)按順序執(zhí)行,一旦遇到文件讀寫、網(wǎng)絡(luò)請(qǐng)求這類耗時(shí)操作,整個(gè)程序就會(huì)被卡住,CPU 資源也只能閑置浪費(fèi)。
而異步編程,堪稱程序世界的 “多車道高速公路”。當(dāng)程序碰到耗時(shí)任務(wù),無需原地等待,可立即切換到其他車道,繼續(xù)執(zhí)行別的任務(wù)。如此一來,CPU 得以充分利用,程序響應(yīng)速度大幅提升,用戶體驗(yàn)自然也更上一層樓。
C++ 作為一門以高性能著稱的編程語言,在異步編程領(lǐng)域底蘊(yùn)深厚,從基礎(chǔ)的多線程技術(shù),到 C++11 引入的 std::async、std::future 等高級(jí)特性,再到 C++20 推出的協(xié)程,為開發(fā)者解鎖高效編程提供了豐富且強(qiáng)大的工具。接下來,就讓我們一同深入 C++ 異步編程的奇妙世界,探索這些工具的用法 。
Part1.異步編程的簡(jiǎn)介
1.1什么是異步?
異步編程是一種編程范式,允許程序在等待某些操作時(shí)繼續(xù)執(zhí)行其它任務(wù),而不是阻塞或等待這些操作完成;異步(Asynchronous, async)是與同步(Synchronous, sync)相對(duì)的概念。
在我們學(xué)習(xí)的傳統(tǒng)單線程編程中,程序的運(yùn)行是同步的(同步不意味著所有步驟同時(shí)運(yùn)行,而是指步驟在一個(gè)控制流序列中按順序執(zhí)行)。而異步的概念則是不保證同步的概念,也就是說,一個(gè)異步過程的執(zhí)行將不再與原有的序列有順序關(guān)系。
簡(jiǎn)單來理解就是:同步按你的代碼順序執(zhí)行,異步不按照代碼順序執(zhí)行,異步的執(zhí)行效率更高。
常見的兩種異步:回調(diào)函數(shù)、異步Ajax
(1)回調(diào)函數(shù)
回調(diào)函數(shù)最常見的是setTimeout,實(shí)例如下:
<script type="text/javascript">
	setTimeout(function() {
		console.log("First")
	}, 2000)
	console.log("Second")
</script>正常情況下(同步)應(yīng)該先輸出First再輸出Second,但結(jié)果剛好相反。因?yàn)檠舆t了2秒,所以在這2秒內(nèi)先輸出了Second,2秒后再輸出了First。
(2)異步Ajax
<button>發(fā)送一個(gè) HTTP GET 請(qǐng)求并獲取返回結(jié)果</button>
<script>
	$(document).ready(function() {
		$("button").click(function() {
			$.get("data.json", function(data, status) {
				console.log("數(shù)據(jù): " + data + "\n狀態(tài): " + status);
			});
			console.log("1111")
		});
	});
</script>1.2同步 VS 異步:編程世界的龜兔賽跑
在編程的奇妙世界里,同步與異步是兩種重要的任務(wù)執(zhí)行方式,就如同龜兔賽跑中的烏龜和兔子,有著截然不同的行事風(fēng)格。
先來說說同步編程,它就像一只穩(wěn)扎穩(wěn)打的烏龜 ,代碼按照順序,一個(gè)任務(wù)接著一個(gè)任務(wù)地執(zhí)行。只有當(dāng)前一個(gè)任務(wù)徹底完成,拿到了它的返回結(jié)果,程序才會(huì)繼續(xù)向下執(zhí)行下一個(gè)任務(wù)。在這個(gè)過程中,如果某個(gè)任務(wù)因?yàn)榈却Y源(比如進(jìn)行網(wǎng)絡(luò)請(qǐng)求、讀取大文件等)而花費(fèi)了大量時(shí)間,整個(gè)程序就只能干等著,其他任務(wù)也都被阻塞,無法推進(jìn) ,就像排隊(duì)買票,必須等前面的人買完,下一個(gè)人才能上前買票。
而異步編程呢,則像是那只靈活的兔子。當(dāng)程序遇到一個(gè)可能會(huì)耗時(shí)的任務(wù)時(shí),它不會(huì)傻等這個(gè)任務(wù)完成,而是先把這個(gè)任務(wù)扔到一邊,自己繼續(xù)去執(zhí)行后續(xù)的代碼。等那個(gè)異步任務(wù)完成了,再通過特定的機(jī)制(比如回調(diào)函數(shù)、事件監(jiān)聽、Promise 等)來通知程序處理結(jié)果。這就好比你點(diǎn)了外賣,下單之后不需要一直盯著手機(jī)等待外賣送達(dá),你可以繼續(xù)做自己的事情,等外賣到了,手機(jī)會(huì)收到通知(回調(diào))。
1.3異步編程為何在 C++ 中如此重要
C++ 作為一門強(qiáng)大的編程語言,在系統(tǒng)級(jí)開發(fā)、游戲開發(fā)、嵌入式系統(tǒng)、高性能計(jì)算等眾多領(lǐng)域都有著廣泛的應(yīng)用 。在這些場(chǎng)景中,異步編程發(fā)揮著舉足輕重的作用。
以系統(tǒng)級(jí)開發(fā)為例,操作系統(tǒng)需要同時(shí)處理多個(gè)任務(wù),如文件讀寫、網(wǎng)絡(luò)通信、用戶輸入等。如果采用同步編程,當(dāng)進(jìn)行文件讀寫時(shí),整個(gè)系統(tǒng)可能會(huì)被阻塞,無法及時(shí)響應(yīng)其他任務(wù),導(dǎo)致系統(tǒng)性能大幅下降。而異步編程可以讓操作系統(tǒng)在等待文件讀寫完成的過程中,繼續(xù)處理其他任務(wù),大大提高了系統(tǒng)的響應(yīng)速度和吞吐量。
在游戲開發(fā)中,為了實(shí)現(xiàn)流暢的畫面和實(shí)時(shí)交互,游戲需要在同一時(shí)間內(nèi)處理圖形渲染、用戶操作、網(wǎng)絡(luò)同步等多個(gè)任務(wù)。異步編程能夠使這些任務(wù)并行執(zhí)行,避免了因某個(gè)任務(wù)的阻塞而影響整個(gè)游戲的運(yùn)行,從而提升了游戲的性能和用戶體驗(yàn)。
在高性能計(jì)算領(lǐng)域,C++ 常用于處理大規(guī)模數(shù)據(jù)和復(fù)雜算法。異步編程可以充分利用多核處理器的優(yōu)勢(shì),將不同的計(jì)算任務(wù)分配到不同的核心上并行執(zhí)行,大大縮短了計(jì)算時(shí)間,提高了計(jì)算效率。
Part2.探索 C++中的異步編程工具
了解了異步編程的重要性之后,接下來就來看看 C++ 中用于實(shí)現(xiàn)異步編程的強(qiáng)大工具。
2.1 std::async:異步編程的得力助手
std::async 是 C++ 標(biāo)準(zhǔn)庫提供的一個(gè)函數(shù)模板,用于異步執(zhí)行任務(wù)。它的基本語法如下:
std::future<返回類型> future = std::async(啟動(dòng)策略, 函數(shù)名, 參數(shù)1, 參數(shù)2, ...);
其中,啟動(dòng)策略 是一個(gè)可選參數(shù),用于指定任務(wù)的執(zhí)行方式,有以下幾種取值:
- std::launch::async:表示任務(wù)將在一個(gè)新線程中異步執(zhí)行。就像你在餐廳點(diǎn)餐,服務(wù)員接到你的訂單后,立即把訂單交給廚房的廚師,廚師在廚房(新線程)里開始為你烹飪美食。
 - std::launch::deferred:任務(wù)會(huì)被延遲執(zhí)行,直到調(diào)用 future.get() 或 future.wait() 時(shí)才會(huì)在調(diào)用線程中執(zhí)行。這就好比服務(wù)員先把你的訂單放在一邊,等你催促(調(diào)用 get 或 wait)的時(shí)候,才開始讓廚師做菜。
 - std::launch::async | std::launch::deferred:這是默認(rèn)策略,由系統(tǒng)決定是立即異步執(zhí)行還是延遲執(zhí)行。
 
如果不指定啟動(dòng)策略,默認(rèn)使用 std::launch::async | std::launch::deferred。
std::async 的返回值是一個(gè) std::future 對(duì)象,通過它可以獲取異步任務(wù)的執(zhí)行結(jié)果 。例如:
#include <iostream>
#include <future>
#include <chrono>
// 模擬一個(gè)耗時(shí)任務(wù)
int heavyTask() {
    std::this_thread::sleep_for(std::chrono::seconds(2)); // 模擬耗時(shí)2秒
    return 42;
}
int main() {
    // 啟動(dòng)異步任務(wù)
    std::future<int> futureResult = std::async(std::launch::async, heavyTask);
    std::cout << "Doing other things while waiting for the task to complete..." << std::endl;
    // 獲取異步任務(wù)的結(jié)果,如果任務(wù)還未完成,get() 會(huì)阻塞等待
    int result = futureResult.get();
    std::cout << "The result of the heavy task is: " << result << std::endl;
    return 0;
}在上面的代碼中,std::async 啟動(dòng)了一個(gè)異步任務(wù) heavyTask,主線程在等待任務(wù)完成的過程中可以繼續(xù)執(zhí)行其他操作,當(dāng)調(diào)用 futureResult.get() 時(shí),如果任務(wù)尚未完成,主線程會(huì)被阻塞,直到任務(wù)完成并返回結(jié)果。
2.2 std::future:獲取異步操作結(jié)果的窗口
std::future 是一個(gè)模板類,用于獲取異步操作的結(jié)果。它就像是一個(gè)窗口,通過這個(gè)窗口可以窺視異步任務(wù)的執(zhí)行狀態(tài)和獲取最終的結(jié)果。std::future 提供了以下幾個(gè)重要的成員函數(shù):
①get():獲取異步操作的結(jié)果。如果異步任務(wù)還未完成,調(diào)用 get() 會(huì)阻塞當(dāng)前線程,直到任務(wù)完成并返回結(jié)果。如果任務(wù)在執(zhí)行過程中拋出了異常,get() 會(huì)重新拋出該異常。例如:
std::future<int> future = std::async([]() {
    return 1 + 2;
});
int result = future.get(); // 阻塞等待任務(wù)完成并獲取結(jié)果
std::cout << "Result: " << result << std::endl;②wait():阻塞當(dāng)前線程,直到異步任務(wù)完成,但不返回結(jié)果。常用于在不關(guān)心結(jié)果,只需要等待任務(wù)完成的場(chǎng)景。比如:
std::future<void> future = std::async([]() {
    // 模擬耗時(shí)操作
    std::this_thread::sleep_for(std::chrono::seconds(3));
});
std::cout << "Waiting for the task to finish..." << std::endl;
future.wait();
std::cout << "Task finished." << std::endl;wait_for():阻塞當(dāng)前線程一段時(shí)間,等待異步任務(wù)完成。返回一個(gè) std::future_status 枚舉值,表示等待的結(jié)果,可能的值有:
- std::future_status::ready:任務(wù)已完成。
 - std::future_status::timeout:等待超時(shí),任務(wù)還未完成。
 - std::future_status::deferred:任務(wù)是延遲執(zhí)行的,還未開始執(zhí)行。
 
std::future<int> future = std::async([]() {
    std::this_thread::sleep_for(std::chrono::seconds(2));
    return 42;
});
std::this_thread::sleep_for(std::chrono::seconds(1)); // 主線程先干點(diǎn)別的
auto status = future.wait_for(std::chrono::seconds(1));
if (status == std::future_status::ready) {
    int result = future.get();
    std::cout << "Task completed, result: " << result << std::endl;
} else if (status == std::future_status::timeout) {
    std::cout << "Task is still in progress." << std::endl;
} else if (status == std::future_status::deferred) {
    std::cout << "Task is deferred." << std::endl;
}wait_until():阻塞當(dāng)前線程直到指定的時(shí)間點(diǎn),等待異步任務(wù)完成。用法與 wait_for() 類似,只是等待的結(jié)束條件是時(shí)間點(diǎn)而不是時(shí)間段。
2.3 std::promise:線程間通信的橋梁
std::promise 也是一個(gè)模板類,它通常與 std::future 搭配使用,用于在不同線程之間傳遞數(shù)據(jù) 。std::promise 可以看作是一個(gè)承諾,它承諾在未來的某個(gè)時(shí)刻會(huì)提供一個(gè)值,而 std::future 則可以獲取這個(gè)承諾的值。
std::promise 的基本原理是:在一個(gè)線程中創(chuàng)建一個(gè) std::promise 對(duì)象,然后將與該 std::promise 關(guān)聯(lián)的 std::future 對(duì)象傳遞給其他線程。在創(chuàng)建 std::promise 的線程中,通過調(diào)用 std::promise 的 set_value() 成員函數(shù)來設(shè)置一個(gè)值(或者調(diào)用 set_exception() 來設(shè)置一個(gè)異常),而在其他持有 std::future 的線程中,可以通過 std::future 的 get() 方法來獲取這個(gè)值(如果設(shè)置的是異常,get() 會(huì)拋出該異常)。
下面是一個(gè)簡(jiǎn)單的示例,展示了如何使用 std::promise 和 std::future 在線程間傳遞數(shù)據(jù):
#include <iostream>
#include <thread>
#include <future>
// 線程函數(shù),設(shè)置 promise 的值
void setPromiseValue(std::promise<int>& promise) {
    std::this_thread::sleep_for(std::chrono::seconds(2)); // 模擬耗時(shí)操作
    promise.set_value(42); // 設(shè)置 promise 的值
}
int main() {
    std::promise<int> promise;
    std::future<int> future = promise.get_future(); // 獲取與 promise 關(guān)聯(lián)的 future
    std::thread thread(setPromiseValue, std::ref(promise)); // 創(chuàng)建線程并傳遞 promise
    std::cout << "Waiting for the result..." << std::endl;
    int result = future.get(); // 阻塞等待,直到 promise 設(shè)置值
    std::cout << "The result is: " << result << std::endl;
    thread.join(); // 等待線程結(jié)束
    return 0;
}在這個(gè)例子中,主線程創(chuàng)建了一個(gè) std::promise<int> 對(duì)象和與之關(guān)聯(lián)的 std::future<int> 對(duì)象。然后創(chuàng)建了一個(gè)新線程 thread,并將 std::promise 對(duì)象傳遞給新線程的函數(shù) setPromiseValue。在新線程中,經(jīng)過一段時(shí)間的模擬耗時(shí)操作后,調(diào)用 promise.set_value(42) 設(shè)置了 std::promise 的值。而主線程在調(diào)用 future.get() 時(shí)會(huì)被阻塞,直到新線程設(shè)置了 std::promise 的值,然后獲取到這個(gè)值并輸出。
2.4 std::packaged_task:封裝可調(diào)用對(duì)象的利器
std::packaged_task 是一個(gè)模板類,用于封裝一個(gè)可調(diào)用對(duì)象(如函數(shù)、lambda 表達(dá)式、函數(shù)對(duì)象等),以便異步執(zhí)行該任務(wù),并通過 std::future 獲取結(jié)果。它的作用是將任務(wù)的執(zhí)行和結(jié)果的獲取分離開來,使得任務(wù)可以在不同的線程中異步執(zhí)行 。
std::packaged_task 的基本原理是:將一個(gè)可調(diào)用對(duì)象封裝在 std::packaged_task 對(duì)象中,當(dāng)調(diào)用 std::packaged_task 對(duì)象時(shí),它會(huì)在后臺(tái)線程中執(zhí)行封裝的可調(diào)用對(duì)象,并將執(zhí)行結(jié)果存儲(chǔ)在一個(gè)共享狀態(tài)中。通過調(diào)用 std::packaged_task 的 get_future() 方法,可以獲取一個(gè)與該共享狀態(tài)關(guān)聯(lián)的 std::future 對(duì)象,從而在其他線程中獲取任務(wù)的執(zhí)行結(jié)果。
例如,假設(shè)有一個(gè)計(jì)算兩個(gè)整數(shù)之和的函數(shù),現(xiàn)在想要異步執(zhí)行這個(gè)計(jì)算任務(wù)并獲取結(jié)果,可以使用 std::packaged_task 來實(shí)現(xiàn):
#include <iostream>
#include <future>
#include <thread>
// 計(jì)算兩個(gè)整數(shù)之和的函數(shù)
int add(int a, int b) {
    return a + b;
}
int main() {
    // 創(chuàng)建一個(gè) packaged_task 對(duì)象,封裝 add 函數(shù)
    std::packaged_task<int(int, int)> task(add);
    // 獲取與 task 關(guān)聯(lián)的 future 對(duì)象,用于獲取任務(wù)結(jié)果
    std::future<int> futureResult = task.get_future();
    // 在新線程中執(zhí)行任務(wù)
    std::thread thread(std::move(task), 3, 5);
    // 主線程可以繼續(xù)執(zhí)行其他操作
    std::cout << "Doing other things while the task is running..." << std::endl;
    // 獲取異步任務(wù)的結(jié)果
    int result = futureResult.get();
    std::cout << "The result of the addition is: " << result << std::endl;
    thread.join(); // 等待線程結(jié)束
    return 0;
}在上述代碼中,首先創(chuàng)建了一個(gè) std::packaged_task<int(int, int)> 對(duì)象 task,并將 add 函數(shù)封裝在其中。然后通過 task.get_future() 獲取了一個(gè) std::future<int> 對(duì)象 futureResult,用于獲取任務(wù)的結(jié)果。接著,創(chuàng)建了一個(gè)新線程 thread,并將 task 移動(dòng)到新線程中執(zhí)行,同時(shí)傳遞了 add 函數(shù)所需的參數(shù) 3 和 5。在主線程中,可以繼續(xù)執(zhí)行其他操作,最后通過 futureResult.get() 獲取異步任務(wù)的結(jié)果并輸出。
Part3.C++ 異步編程案例分析
3.1案例一:異步文件讀取
在實(shí)際應(yīng)用中,文件讀取是一個(gè)常見的操作,尤其是在處理大文件時(shí),如果采用同步讀取方式,可能會(huì)導(dǎo)致程序長(zhǎng)時(shí)間阻塞,影響用戶體驗(yàn)。下面通過一個(gè)示例來展示如何使用 std::async 和 std::future 實(shí)現(xiàn)異步文件讀取,并分析其性能優(yōu)勢(shì)。
假設(shè)我們有一個(gè)大小為 1GB 的大文件 large_file.txt,需要讀取其內(nèi)容。首先,使用同步方式讀取文件的代碼如下:
#include <iostream>
#include <fstream>
#include <chrono>
int main() {
    auto start = std::chrono::high_resolution_clock::now();
    std::ifstream file("large_file.txt");
    std::string content;
    file.seekg(0, std::ios::end);
    content.resize(file.tellg());
    file.seekg(0, std::ios::beg);
    file.read(&content[0], content.size());
    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
    std::cout << "Synchronous read time: " << duration << " ms" << std::endl;
    return 0;
}在上述代碼中,std::ifstream 用于打開文件,通過 seekg 和 tellg 函數(shù)獲取文件大小并分配相應(yīng)的內(nèi)存空間,然后使用 read 函數(shù)將文件內(nèi)容讀取到字符串 content 中。整個(gè)過程是同步的,程序會(huì)阻塞直到文件讀取完成。
接下來,使用異步方式讀取文件:
#include <iostream>
#include <fstream>
#include <future>
#include <chrono>
std::string readFileAsync(const std::string& filename) {
    std::ifstream file(filename);
    std::string content;
    file.seekg(0, std::ios::end);
    content.resize(file.tellg());
    file.seekg(0, std::ios::beg);
    file.read(&content[0], content.size());
    return content;
}
int main() {
    auto start = std::chrono::high_resolution_clock::now();
    // 啟動(dòng)異步任務(wù)讀取文件
    std::future<std::string> futureContent = std::async(std::launch::async, readFileAsync, "large_file.txt");
    // 主線程可以在等待文件讀取的過程中執(zhí)行其他操作
    std::cout << "Doing other things while reading the file..." << std::endl;
    // 獲取異步任務(wù)的結(jié)果
    std::string content = futureContent.get();
    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
    std::cout << "Asynchronous read time: " << duration << " ms" << std::endl;
    return 0;
}在這個(gè)異步讀取的示例中,定義了一個(gè) readFileAsync 函數(shù),用于讀取文件內(nèi)容。通過 std::async 啟動(dòng)一個(gè)異步任務(wù)來執(zhí)行這個(gè)函數(shù),并返回一個(gè) std::future<std::string> 對(duì)象,用于獲取異步任務(wù)的結(jié)果。在主線程中,調(diào)用 futureContent.get() 之前,可以執(zhí)行其他操作,當(dāng)調(diào)用 get() 時(shí),如果文件尚未讀取完成,主線程會(huì)被阻塞,直到讀取完成并返回結(jié)果。
通過多次測(cè)試,對(duì)比同步和異步讀取大文件的時(shí)間,發(fā)現(xiàn)異步讀取方式在讀取大文件時(shí),雖然整體耗時(shí)可能不會(huì)有明顯的減少(因?yàn)槲募x取本身的 I/O 操作是耗時(shí)的主要因素),但它可以讓主線程在等待文件讀取的過程中繼續(xù)執(zhí)行其他任務(wù),提高了程序的響應(yīng)性和整體效率 。例如,在一個(gè)圖形界面應(yīng)用中,使用異步文件讀取可以避免界面在讀取大文件時(shí)出現(xiàn)卡頓現(xiàn)象,用戶可以繼續(xù)進(jìn)行其他操作,如點(diǎn)擊按鈕、切換界面等。
3.2案例二:多線程數(shù)據(jù)處理
在多線程數(shù)據(jù)處理場(chǎng)景中,經(jīng)常會(huì)遇到需要多個(gè)線程協(xié)同工作,共同處理一批數(shù)據(jù)的情況。同時(shí),也會(huì)面臨共享數(shù)據(jù)競(jìng)爭(zhēng)和線程同步等問題。下面通過一個(gè)示例來展示如何使用 std::thread 和 std::mutex 實(shí)現(xiàn)多線程數(shù)據(jù)處理,并解決共享數(shù)據(jù)競(jìng)爭(zhēng)和線程同步問題。
假設(shè)我們有一個(gè)包含 10000 個(gè)整數(shù)的數(shù)組,需要對(duì)每個(gè)元素進(jìn)行平方運(yùn)算,然后將結(jié)果存儲(chǔ)到另一個(gè)數(shù)組中。首先,使用單線程處理的代碼如下:
#include <iostream>
#include <vector>
#include <chrono>
void squareArraySingleThread(std::vector<int>& input, std::vector<int>& output) {
    for (size_t i = 0; i < input.size(); ++i) {
        output[i] = input[i] * input[i];
    }
}
int main() {
    std::vector<int> input(10000);
    std::vector<int> output(10000);
    for (int i = 0; i < 10000; ++i) {
        input[i] = i + 1;
    }
    auto start = std::chrono::high_resolution_clock::now();
    squareArraySingleThread(input, output);
    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
    std::cout << "Single - thread processing time: " << duration << " ms" << std::endl;
    return 0;
}上述代碼中,squareArraySingleThread 函數(shù)使用單線程遍歷輸入數(shù)組,對(duì)每個(gè)元素進(jìn)行平方運(yùn)算,并將結(jié)果存儲(chǔ)到輸出數(shù)組中。
接下來,使用多線程處理:
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <chrono>
std::mutex mutex_;
void squareArrayMultiThread(std::vector<int>& input, std::vector<int>& output, int start, int end) {
    for (int i = start; i < end; ++i) {
        std::lock_guard<std::mutex> lock(mutex_);
        output[i] = input[i] * input[i];
    }
}
int main() {
    std::vector<int> input(10000);
    std::vector<int> output(10000);
    for (int i = 0; i < 10000; ++i) {
        input[i] = i + 1;
    }
    auto start = std::chrono::high_resolution_clock::now();
    const int numThreads = 4;
    std::vector<std::thread> threads;
    int chunkSize = input.size() / numThreads;
    for (int i = 0; i < numThreads; ++i) {
        int startIndex = i * chunkSize;
        int endIndex = (i == numThreads - 1)? input.size() : (i + 1) * chunkSize;
        threads.emplace_back(squareArrayMultiThread, std::ref(input), std::ref(output), startIndex, endIndex);
    }
    for (auto& thread : threads) {
        thread.join();
    }
    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
    std::cout << "Multi - thread processing time: " << duration << " ms" << std::endl;
    return 0;
}在多線程處理的代碼中,定義了 squareArrayMultiThread 函數(shù),該函數(shù)負(fù)責(zé)處理數(shù)組的一部分元素。通過 std::thread 創(chuàng)建多個(gè)線程,每個(gè)線程處理數(shù)組的一個(gè)分塊。為了避免多個(gè)線程同時(shí)訪問和修改輸出數(shù)組時(shí)出現(xiàn)數(shù)據(jù)競(jìng)爭(zhēng)問題,使用了 std::mutex 互斥鎖。std::lock_guard<std::mutex> lock(mutex_); 語句使用了 RAII(Resource Acquisition Is Initialization)機(jī)制,在構(gòu)造時(shí)自動(dòng)鎖定互斥鎖,在析構(gòu)時(shí)自動(dòng)解鎖,確保了在訪問共享數(shù)據(jù)時(shí)的線程安全性。
通過多次測(cè)試,對(duì)比單線程和多線程處理數(shù)據(jù)的時(shí)間,發(fā)現(xiàn)多線程處理在處理大量數(shù)據(jù)時(shí)具有明顯的性能優(yōu)勢(shì)。因?yàn)槎嗑€程可以充分利用多核處理器的優(yōu)勢(shì),將任務(wù)分配到不同的核心上并行執(zhí)行,從而大大縮短了處理時(shí)間 。但需要注意的是,線程的創(chuàng)建和管理也會(huì)消耗一定的資源,當(dāng)數(shù)據(jù)量較小時(shí),多線程處理可能會(huì)因?yàn)榫€程調(diào)度等開銷而導(dǎo)致性能反而不如單線程。此外,合理地劃分任務(wù)分塊大小也會(huì)對(duì)性能產(chǎn)生影響,需要根據(jù)實(shí)際情況進(jìn)行優(yōu)化。















 
 
 














 
 
 
 