C++ 中實現 `Task::WhenAll` 和 `Task::WhenAny` 的兩種方案

📚 C++ 中實現 Task::WhenAllTask::WhenAny 的兩種方案

引用

  1. 拈朵微笑的花 想一番人世變換 到頭來輸贏又何妨
  2. 日與夜互消長 富與貴難久長 今早的容顏老於昨晚
  3. C++ 標準庫異步編程示例(一)
  4. C++ TAP(基于任務的異步編程模式)

🚀 引言:異步編程的需求與挑戰

在現代軟件開發中,異步編程已成為提升應用性能的關鍵技術。C# 提供了優雅的 Task.WhenAllTask.WhenAny 機制來管理多個異步任務,但 C++ 標準庫中缺乏直接等效功能。本文將深入探討兩種高效實現方案:

異步編程需求
WhenAll 實現
WhenAny 實現
簡單輪詢方案
高效條件變量方案
簡單輪詢方案
高效條件變量方案

🔄 方案1:基于輪詢的簡單實現

🛠? when_all 實現(簡單輪詢)

#include <vector>
#include <future>template <typename T>
std::vector<T> when_all(std::vector<std::future<T>>& futures) {std::vector<T> results;for (auto& fut : futures) {results.push_back(fut.get());}return results;
}// void 特化版本
void when_all(std::vector<std::future<void>>& futures) {for (auto& fut : futures) {fut.get();}
}
原理說明
  • 順序執行:循環遍歷每個 future,調用 get() 方法阻塞等待結果
  • 結果收集:對于非 void 任務,結果存儲在 vector 中返回
  • 優點:實現簡單,代碼直觀
  • 缺點:順序等待導致性能瓶頸

🛠? when_any 實現(輪詢方式)

#include <chrono>
#include <vector>
#include <future>template <typename T>
size_t when_any(std::vector<std::future<T>>& futures) {while (true) {for (size_t i = 0; i < futures.size(); ++i) {if (futures[i].wait_for(std::chrono::seconds(0)) == std::future_status::ready) {return i;}}std::this_thread::sleep_for(std::chrono::milliseconds(10));}
}
原理說明
  • 輪詢檢測:使用 wait_for(0) 非阻塞檢查任務狀態
  • 指數退避:每次檢測后休眠減少 CPU 占用
  • 返回索引:返回第一個完成任務的索引
  • 缺點:CPU 占用高,響應延遲(最大10ms)
開始
遍歷所有future
是否ready?
返回索引
休眠10ms

? 方案2:基于條件變量的高效實現

🧩 WhenAll 類設計(高效等待所有任務)

#include <vector>
#include <future>
#include <mutex>
#include <condition_variable>
#include <thread>class WhenAll {
public:void add_future(std::future<void> fut) {std::lock_guard<std::mutex> lock(mtx);futures.push_back(std::move(fut));count++;}void wait() {std::unique_lock<std::mutex> lock(mtx);if (count == 0) return;for (auto& fut : futures) {std::thread([&, this] {fut.wait();std::lock_guard<std::mutex> lock(mtx);if (--count == 0) cv.notify_all();}).detach();}cv.wait(lock, [this] { return count == 0; });}private:std::vector<std::future<void>> futures;std::mutex mtx;std::condition_variable cv;int count = 0;
};
架構解析
WhenAll
- futures: vector>
- mtx: mutex
- cv: condition_variable
- count: int
+add_future(future fut)
+wait()
工作原理
  1. 添加任務:通過 add_future 添加異步任務
  2. 監控線程:為每個任務創建監控線程
  3. 條件等待:主線程等待條件變量 cv
  4. 完成通知:最后完成的任務觸發 notify_all()
  5. 資源釋放:監控線程自動分離(detach
性能優勢
  • 零輪詢:完全消除CPU空轉
  • 即時響應:任務完成立即通知
  • 線程安全:互斥鎖保護共享狀態

🧩 WhenAny 類設計(高效等待任意任務)

#include <vector>
#include <future>
#include <mutex>
#include <condition_variable>template <typename T>
class WhenAny {
public:template <typename Func>void add_task(Func func) {std::lock_guard<std::mutex> lock(mtx);futures.push_back(std::async(std::launch::async, [this, func] {auto result = func();{std::lock_guard<std::mutex> lock(mtx);if (!completed) {completed = true;completed_index = futures.size() - 1;cv.notify_all();}}return result;}));}size_t wait() {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, [this] { return completed; });return completed_index;}std::future<T>& get_future(size_t index) {return futures[index];}private:std::vector<std::future<T>> futures;std::mutex mtx;std::condition_variable cv;bool completed = false;size_t completed_index = 0;
};
架構解析
WhenAny
- futures: vector>
- mtx: mutex
- cv: condition_variable
- completed: bool
- completed_index: size_t
+add_task(Func func)
+wait()
+get_future(size_t index)
工作流程
主線程任務線程WhenAny對象add_task(任務1)啟動異步任務add_task(任務2)啟動異步任務wait()任務完成返回完成索引主線程任務線程WhenAny對象
關鍵特性
  1. 泛型支持:模板化設計支持任意返回類型
  2. 一次性通知completed 標志確保只通知一次
  3. 結果獲取get_future 方法獲取已完成任務的結果
  4. 線程安全:互斥鎖保護共享狀態

🧪 使用示例與場景分析

基本使用示例

#include <iostream>
#include <chrono>
#include <thread>int main() {// 示例1: WhenAll 使用WhenAll wa;wa.add_future(std::async([] { std::this_thread::sleep_for(std::chrono::seconds(1));std::cout << "任務1完成\n";}));wa.add_future(std::async([] { std::this_thread::sleep_for(std::chrono::seconds(2));std::cout << "任務2完成\n"; }));std::cout << "等待所有任務...\n";wa.wait();std::cout << "所有任務完成!\n";// 示例2: WhenAny 使用WhenAny<int> wany;wany.add_task([] {std::this_thread::sleep_for(std::chrono::seconds(3));return 100;});wany.add_task([] {std::this_thread::sleep_for(std::chrono::seconds(1));return 200;});std::cout << "等待任意任務完成...\n";size_t index = wany.wait();auto& fut = wany.get_future(index);std::cout << "任務" << index << "最先完成,結果: " << fut.get() << "\n";return 0;
}

實際應用場景

  1. 微服務聚合:并行調用多個微服務,等待所有響應
  2. 競態條件處理:多個數據源查詢,使用第一個返回結果
  3. 資源加載:并行加載多個資源文件,等待全部完成
  4. 超時處理:多個備用服務調用,使用最先響應的服務

🚀 高級優化與擴展

性能優化技術

  1. 線程池集成:避免為每個任務創建新線程

    void wait(ThreadPool& pool) {std::unique_lock<std::mutex> lock(mtx);if (count == 0) return;for (auto& fut : futures) {pool.enqueue([&, this] {fut.wait();std::lock_guard<std::mutex> lock(mtx);if (--count == 0) cv.notify_all();});}cv.wait(lock, [this] { return count == 0; });
    }
    
  2. 共享future優化:避免多次get()調用

    void add_future(std::shared_future<void> shared_fut) {std::lock_guard<std::mutex> lock(mtx);shared_futures.push_back(shared_fut);count++;
    }
    
  3. 批量任務添加:減少鎖競爭

    void add_futures(const std::vector<std::future<void>>& new_futures) {std::lock_guard<std::mutex> lock(mtx);futures.insert(futures.end(), new_futures.begin(), new_futures.end());count += new_futures.size();
    }
    

功能擴展

  1. 超時支持:添加 wait_forwait_until

    template <typename Rep, typename Period>
    bool wait_for(const std::chrono::duration<Rep, Period>& timeout) {std::unique_lock<std::mutex> lock(mtx);return cv.wait_for(lock, timeout, [this] { return count == 0; });
    }
    
  2. 混合類型支持:使用 std::variant

    class WhenAnyVariant {
    public:template <typename Func>void add_task(Func func) {using ResultType = decltype(func());std::lock_guard<std::mutex> lock(mtx);futures.push_back(std::async(std::launch::async, [=] {auto result = func();{std::lock_guard<std::mutex> lock(mtx);if (!completed) {completed = true;completed_index = futures.size() - 1;cv.notify_all();}}return std::variant<ResultType>(std::move(result));}));}// ... 其他成員
    private:std::vector<std::future<std::variant<int, double, std::string>>> futures;
    };
    
  3. 進度追蹤:添加進度回調

    void wait(std::function<void(int)> progress_callback) {std::unique_lock<std::mutex> lock(mtx);if (count == 0) return;for (auto& fut : futures) {std::thread([&, this] {fut.wait();std::lock_guard<std::mutex> lock(mtx);progress_callback(++completed_count);if (completed_count == count) cv.notify_all();}).detach();}cv.wait(lock, [this] { return completed_count == count; });
    }
    

?? 注意事項與最佳實踐

異常處理

void add_future(std::future<void> fut) {std::lock_guard<std::mutex> lock(mtx);futures.push_back(std::async(std::launch::async, [fut = std::move(fut)]() mutable {try {fut.get();} catch (const std::exception& e) {std::cerr << "任務異常: " << e.what() << std::endl;}}));count++;
}

資源管理最佳實踐

  1. 避免線程泄漏:使用RAII包裝線程
  2. 預防死鎖:鎖粒度最小化
  3. 內存安全:使用智能指針管理共享數據
  4. 性能監控:添加任務執行時間統計

平臺適配性

  1. 跨平臺考慮:使用標準庫確保可移植性
  2. 編譯器支持:確保C++17及以上特性
  3. 異步模型:與平臺特定API(如IOCP/epoll)集成

📊 性能對比分析

方案類型CPU占用響應延遲內存開銷適用場景
簡單輪詢高 (持續10-100%)高 (10ms級)任務少、低頻率
條件變量低 (<1%)低 (μs級)高并發、實時系統
線程池集成中 (可控)低 (μs級)大規模任務處理

在這里插入圖片描述

🔮 未來發展與C++標準展望

C++23/26異步特性

  1. std::execution:標準執行器支持
  2. 協程增強:更簡潔的異步代碼編寫
  3. 網絡庫集成:與標準網絡庫協同工作

社區解決方案

  1. Boost.Asio:提供 async_wait_all 等實用工具
  2. Folly庫:Facebook的高性能異步工具集
  3. Qt Concurrent:跨平臺異步框架

💎 總結

本文詳細探討了在C++中實現 Task.WhenAllTask.WhenAny 的兩種核心方案:

  1. 簡單輪詢方案:適用于輕量級場景,實現簡單但效率較低
  2. 條件變量方案:高性能實現,適用于生產環境
    • 零輪詢設計減少CPU占用
    • 即時響應確保最佳性能
    • 擴展性強,支持超時、進度回調等高級功能
少量任務
大量任務
高實時性
可接受延遲
選擇實現方案
任務數量
簡單輪詢方案
實時性要求
條件變量方案
線程池集成方案

最佳實踐建議

  • 小型工具類使用簡單輪詢方案
  • 高性能服務器使用條件變量方案
  • 大規模并行處理集成線程池
  • 始終考慮異常安全和資源管理

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/90764.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/90764.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/90764.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【學習】Codeforces Global Round 15 C. Maximize the Intersections

題意&#xff1a;給出一個圓&#xff0c;順時針排布1~2*n&#xff0c;已知連了k條邊&#xff0c;問這個圓最好情況下有多少個線的交點&#xff0c;要求線與線之間不能有重復的連接點&#xff0c;也就是每個點只能被一條線連接 思路&#xff1a; 1.考慮沒有線的時候&#xff0…

圖論:Dijkstra算法

昨天介紹了最小生成樹的兩個算法&#xff0c;最小生成樹的兩個算法旨在求解無向有權圖中的最小代價聯通圖的問題&#xff0c;那么對于有向有權圖&#xff0c;從起點到終點的最小花費代價問題就可以用 Dijkstra 算法來解決而且Dijkstra算法可以求出來從起始點開始到所有節點的最…

WPFC#超市管理系統(2)顧客管理、供應商管理、用戶管理

超市管理系統3. 顧客管理3.1 顧客新增3.2 DataGrid樣式3.3 顧客刪除3.4 顧客修改4. 供應商管理4.1 供應商管理主界面4.2 新增供應商4.3 修改供應商5. 用戶管理5.1 用戶管理主界面5.2 新增用戶5.3 修改用戶總結3. 顧客管理 在CustomerView.xaml使用命令綁定方式添加頁面加載Loa…

Windows本地部署DeepSeek

1、Ollama1、下載Ollama安裝包https://ollama.com/download&#xff08;如果下載很慢 可以直接找我拿安裝包&#xff09;2、使用命令行安裝打開cmd 將下載的安裝包OllamaSetup.exe 放到想要安裝的目錄下。&#xff08;如果直接雙擊&#xff0c;會裝到C盤&#xff09;例如想裝到…

基于Python的新聞爬蟲:實時追蹤行業動態

引言 在信息時代&#xff0c;行業動態瞬息萬變。金融從業者需要實時了解政策變化&#xff0c;科技公司需要跟蹤技術趨勢&#xff0c;市場營銷人員需要掌握競品動向。傳統的人工信息收集方式效率低下&#xff0c;難以滿足實時性需求。Python爬蟲技術為解決這一問題提供了高效方…

阿里視頻直播解決方案VS(MediaMTX + WebRTC) 流媒體解決方案

背景&#xff1a; 公司采購了新的攝像頭&#xff0c;通過rtsp或者rtmp推流到云平臺&#xff0c;云平臺內部進行轉碼處理&#xff0c;客戶端使用HLS或HTTP-FLV播放&#xff0c;移動App可能使用HLS或私有SDK&#xff0c;超低延時則采用WebRTC。 技術選型&#xff1a; RTSP&…

day33:零基礎學嵌入式之網絡——TCP并發服務器

一、服務器1.服務器分類單循環服務器&#xff1a;只能處理一個客戶端任務的服務器并發服務器&#xff1a;可同時處理多個客戶端任務的服務器二、TCP并發服務器的構建1.如何構建&#xff1f;&#xff08;1&#xff09;多進程&#xff08;每一次創建都非常耗時耗空間&#xff0c;…

VR全景制作的流程?VR全景制作可以用在哪些領域?

VR全景制作的流程&#xff1f;VR全景制作可以用在哪些領域&#xff1f;VR全景制作&#xff1a;流程、應用與未來虛擬現實&#xff08;VR&#xff09;全景制作正迅速改變我們的感官體驗&#xff0c;使我們能夠身臨其境地探索虛擬世界&#xff0c;享受沉浸式的奇妙感受。那么&…

用LangChain重構客服系統:騰訊云向量數據庫+GPT-4o實戰

人們眼中的天才之所以卓越非凡&#xff0c;并非天資超人一等而是付出了持續不斷的努力。1萬小時的錘煉是任何人從平凡變成超凡的必要條件。———— 馬爾科姆格拉德威爾 目錄 一、傳統客服系統痛點與重構價值 1.1 傳統方案瓶頸分析 1.2 新方案技術突破點 二、系統架構設計&…

主要分布在腹側海馬體(vHPC)CA1區域(vCA1)的混合調諧細胞(mixed-tuning cells)對NLP中的深層語義分析的積極影響和啟示

腹側海馬體CA1區&#xff08;vCA1&#xff09;的混合調諧細胞&#xff08;mixed-tuning cells&#xff09;通過整合情感、社會關系、空間概念等多模態信息&#xff0c;形成動態的情景化語義表征&#xff0c;為自然語言處理&#xff08;NLP&#xff09;的深層語義分析提供了重要…

ESP32的ADF詳解:6. Audio Processing的API

一、Downmix 1. 核心功能 將基礎音頻流和新加入音頻流混合為單一輸出流&#xff0c;支持動態增益控制和狀態轉換。輸出聲道數與基礎音頻一致&#xff0c;新加入音頻自動轉換聲道匹配。2. 關鍵特性聲道處理 輸出聲道數 基礎音頻聲道數新加入音頻自動轉換聲道&#xff08;如立體…

Qt(基本組件和基本窗口類)

一、基本組件1. Designer設計師為什么要上來先將這個東西呢&#xff0c;這個是QT外置的設計界面的工具&#xff0c;沒啥用&#xff0c;所以了解一下。我們用的多的是QT內置的界面設計&#xff0c;只需要我們雙擊我們創建的項目的.ui文件就可以進入這個界面&#xff0c;你對界面…

docker與k8s的容器數據卷

Docker容器數據卷 特性 docker鏡像由多個只讀層疊加而成&#xff0c;啟動容器時&#xff0c;Docker會加載只讀鏡像層并在鏡像棧頂部添加一個讀寫層。如果運行中的容器修改了現有的一個已經存在的文件&#xff0c;那么該文件將會從讀寫層下面的只讀層復制到讀寫層&#xff0c;該…

自然語言處理技術應用領域深度解析:從理論到實踐的全面探索

1. 引言:自然語言處理的技術革命與應用前景 自然語言處理(Natural Language Processing,NLP)作為人工智能領域的核心分支,正在以前所未有的速度改變著我們的數字化生活。從最初的規則基礎系統到如今基于深度學習的大語言模型,NLP技術經歷了從理論探索到實際應用的深刻變…

OpenGLRender開發記錄(二): 陰影(shadowMap,PCF,PCSS)

目錄已實現功能陰影shadowMapPCFPCSS實現shadowMapPCFPCSS陰影GitHub主頁&#xff1a;https://github.com/sdpyy1 OpenGLRender:https://github.com/sdpyy1/CppLearn/tree/main/OpenGL 已實現功能 除了上次實現IBL之外&#xff0c;項目目前新增了imGUI的渲染&#xff0c;更方便…

Linux:日志亂碼

1、Linux日志亂碼可能是XShell客戶端編碼沒設置為UTF-8引起的&#xff0c;按照以下步驟&#xff0c;設置終端格式&#xff1a;中文版&#xff1a;打開Xshell會話屬性&#xff08;文件→屬性→終端→編碼&#xff09;&#xff0c;選擇與服務器一致的編碼格式&#xff08;如UTF-8…

Rouge:面向摘要自動評估的召回導向型指標——原理、演進與應用全景

“以n-gram重疊量化文本生成質量&#xff0c;為摘要評估提供可計算標尺” Rouge&#xff08;Recall-Oriented Understudy for Gisting Evaluation&#xff09; 是由 南加州大學信息科學研究所&#xff08;ISI&#xff09;的Chin-Yew Lin 于2004年提出的自動文本摘要評估指標&am…

[STM32][HAL]stm32wbxx 超聲波測距模塊實現(HY-SRF05)

前言 在電子技術應用中,距離測量是一個常見且重要的需求。超聲波模塊因其測量精度較高、成本較低、易于使用等優點,被廣泛應用于機器人避障、液位檢測、智能停車系統等領域。該文主要講解以stm32wb芯片為主控,用HAL庫來對HY-SRF05超聲波模塊進行代碼編寫,實現基本的驅動和測…

MySQL 性能調優實戰指南:從診斷到優化全解析

引言在日常的數據庫運維工作中&#xff0c;我們經常需要對 MySQL 數據庫進行診斷和性能分析。本文將介紹一套全面的 MySQL 診斷腳本&#xff0c;適用于 MySQL 8.0&#xff08;兼容 8.0.15 及以上版本&#xff09;&#xff0c;涵蓋事務鎖分析、性能瓶頸定位、配置檢查、連接狀態…

8. 狀態模式

目錄一、應用背景二、狀態模式2.1 解決的問題2.2 角色2.3 實現步驟三、通用設計類圖四、實現4.1 設計類圖4.2 狀態轉換圖4.3 代碼實現一、應用背景 某對象發生變化時&#xff0c;其所能做的操作也隨之變化。應用程序的可維護性和重用性差代碼的邏輯較復雜 二、狀態模式 2.1 …