C++非同步程式設計最佳實踐
Mapreduce問題
多個資料,進行同型別計算,最後彙總結果,怎樣用C++解鎖此類問題?
這個最簡單了,單執行緒迴圈處理每份資料好了。
這有何難,建立一塊地方,針對每份資料建立個執行緒執行計算,將結果寫入先前建立的資料的對應地方,等各執行緒結束,完活。
上面的說法都對,只是不夠好。
對於單執行緒處理,在這個多核時代,未免大馬拉小車,有點浪費CPU。當問題規模變大,你準備花多長時間計算。
對於多執行緒這個說法,從策略上來說,沒有問題。但問題是你不得不手動啟動執行緒,把結果放到共享記憶體裡,通過thread.join()等待結束。這點操作難度,對於我大C++開發來說算啥,分分鐘就搞定了。但問題又來了,現在你的老闆問你要針對單份資料的處理函式,返回結果。
呵呵,原來的單份資料處理函式,十有八九長成這樣:
RetType deal(Indata t,Retdata& r)
{
r=balabala;
}
為多執行緒搞的那個為向主執行緒傳遞結果,不得不處理共享記憶體,現在你又要函式式操作,這絕逼不能夠啊,於是乎,你不得不又寫了一個:
RetType deal(Indata t)
{
Retdata r;
deal(t,r);
return r;
}
呵呵,我似乎聞到了壞程式碼的味道。
更好的方式
C++11中提供了操作多執行緒的高層次特性。
- std::packaged_task 包裝的是一個非同步操作,相當與外包任務,好比我大阿里把電話客服外包給某某公司。
- std::future 提供了一個訪問非同步操作結果的機制,這個是底層機制,在packaged_task和promise內部都有future來訪問結果。
說的比較乾巴,還是上程式碼吧!
#include <iostream>
#include<vector>
#include <future>
using namespace std;
long long jiechen(int n)
{
long long ret=1;
for (int i=1;i<=n; i++)
ret*=i;
return ret;
}
int main()
{
vector<int> data={9,11,13,17,19};
vector<future<long long>> fus;
for (auto i:data)
{
packaged_task<long long() > pt(bind(jiechen,i));
fus.push_back(std::move(pt.get_future()));
std::thread(std::move(pt)).detach();
}
for(auto& i:fus)
{
i.wait();
cout<<i.get()<<endl;
}
return 0;
}
比較簡單,就沒必要解釋了。跟“古老”的方案比,還是有些不同的
1. 不關心執行緒建立和結束
2. 使用層面無共享資料,這個意味著寫子執行緒函式時你不用小心翼翼擔心執行緒安全問題。
3. 抽象層次不同,古老方案本質上還是依靠負作用程式設計,新標準非同步方式則某種程度上跳出了這個範疇。
4,如有異常發生,新方案可以在外層處理異常。
上面說了那麼多,肯定還是有同學說,引入概念(計算機領域的概念真是多啊),變的難理解了,那有我直接操作執行緒幹活爽。我又想要好處,又想好理解,有簡單的方式嗎,有簡單的方式嗎,有簡單的方式嗎?
還真有:std::async
最佳實踐
std::async的原型async(std::launch::async | std::launch::deferred, f, args...)
std::launch::async:在呼叫async就開始建立執行緒。
std::launch::deferred:延遲載入方式建立執行緒。呼叫async時不建立執行緒,直到呼叫了future的get或者wait時才建立執行緒。
std::async是讓大家透懶的,工作過程是這樣的:async先將非同步操作用packaged_task包裝起來,然後將非同步操作的結果放到std::promise中,這個過程就是創造未來的過程。外面再通過future.get/wait來獲取這個未來的結果。完全可以理解為:async(func,args).get()
就是啟動執行緒執行func並獲取返回值。
應用這個特性,上面的主執行緒程式碼變為:
int main()
{
vector<int> data={9,11,13,17,19};
vector<future<long long>> fus;
for (auto i:data) fus.push_back(std::async(jiechen,i));
for(auto& i:fus)
{
i.wait();
cout<<i.get()<<endl;
}
return 0;
}
std:async 不是弄出來搗亂的玩意,真的是非同步程式設計利器,至少,在跨平臺時不用改程式碼不是。在專案中,大家應該盡力避免直接呼叫低層次介面,直接呼叫async建立新執行緒。
以上是一家之言,難免偏頗,歡迎探討。
相關文章
- 非同步程式設計最佳實踐非同步程式設計
- C++程式設計最佳實踐(轉)C++程式設計
- jQuery程式設計的最佳實踐jQuery程式設計
- C 程式設計最佳實踐(轉)程式設計
- 深入實踐c++模板程式設計C++程式設計
- go 程式設計師的最佳實踐Go程式設計師
- PHP安全程式設計最佳實踐PHP程式設計
- 函數語言程式設計最佳實踐函數程式設計
- Laravel最佳實踐–事件驅動程式設計Laravel事件程式設計
- Laravel 最佳實踐 -- 事件驅動程式設計Laravel事件程式設計
- Laravel最佳實踐 -- 事件驅動程式設計Laravel事件程式設計
- Python程式設計規範+最佳實踐Python程式設計
- C#非同步程式設計:原理與實踐C#非同步程式設計
- Java程式設計師的八個最佳實踐Java程式設計師
- 淺談Swift網路程式設計最佳實踐Swift程式設計
- python 網路程式設計----非阻塞或非同步程式設計Python程式設計非同步
- [譯] 非同步程式設計:阻塞與非阻塞非同步程式設計
- SOA 非功能測試最佳實踐
- 孟巖談《C++程式設計原理與實踐》C++程式設計
- 領域驅動設計最佳實踐--程式碼篇
- [01] C#網路程式設計的最佳實踐C#程式設計
- TypeScript 資料模型層程式設計的最佳實踐TypeScript模型程式設計
- Java程式設計細節之十個最佳實踐Java程式設計
- 頂級程式設計師的10條最佳實踐程式設計師
- C++ concurrency::task實現非同步程式設計(WindowsC++非同步程式設計Windows
- 設計微服務的最佳實踐微服務
- react 設計模式與最佳實踐React設計模式
- MaxCompute表設計最佳實踐
- RESTful API 設計指南——最佳實踐RESTAPI
- Android 路由設計最佳實踐Android路由
- Socket程式設計中的同步、非同步、阻塞和非阻塞(轉)程式設計非同步
- 我拒絕接受的幾個最佳程式設計實踐方法程式設計
- Go程式設計實踐Go程式設計
- 【DATAGUARD】Dataguard遠端同步配置最佳實踐
- C++程式設計實現C++程式設計
- 《JAVA併發程式設計實戰》原子變數和非阻塞同步機制Java程式設計變數
- vSAN 設計、部署、運維最佳實踐運維
- 13 個設計 REST API 的最佳實踐RESTAPI