什么是異步
異步是當一個調用請求發送給被調用者,而調用者不用等待其結果的返回.實現異步可以采用多線程技術或則交給另外的進程來處理
異步的優缺點
1、在設計良好的情況下,可以不是使用或減少共享變量的使用,減少了死鎖的可能
2、編寫異步操作的復雜度高,使用回調函數處理難以調試
異步與多線程
異步與多線程,從辯證關系上來看,異步和多線程並不時一個同等關系,異步是目的,多線程只是我們實現異步的一個手段(線程池).
硬件上實現異步
DMA就是直 接內存訪問的意思,也就是說,擁有DMA功能的硬件在和內存進行數據交換的時候可以不消耗CPU資源。只要CPU在發起數據傳輸時發送一個指令,
硬件就開 始自己和內存交換數據,在傳輸完成之后硬件會觸發一個中斷來通知操作完成。這些無須消耗CPU時間的I/O操作正是異步操作的硬件基礎。
軟件上實現異步
上面說了多線程是實現異步的一個手段、但是使用主函數調用異步處理線程的時候,比較難獲取子線程的返回值(實際可以通過使用全局變量、指針、引用、promise+future),總體來說使用比較復雜,所以就有async()函數實現異步
std::async是更高層次上的異步操作,使我們不用關注線程創建內部細節,就能方便的獲取異步執行狀態和結果,還可以指定線程創建策略,應該用std::async替代線程的創建,讓它成為我們做異步操作的首選。
async大概的工作過程是這樣的:
1、furture聲明未來的異步操作的結果
2、promise承諾這個結果的出現
3、packaged_task將異步任務包裝起來,放到線程中執行(lambda 表達式)
4、最后通過wait()和wait_for()來獲取異步任務的完成狀態,根據這個狀態選擇調用get()來獲取這個未來的結果
因為一個異步操作我們是不可能馬上就獲取操作結果的,只能在未來某個時候獲取,但是我們可以以同步等待的方式來獲取結果,可以通過查詢future的狀態(future_status)來獲取異步操作的結果。
future_status是一個枚舉的數據類型,有三種狀態:
1、deferred:異步操作還沒開始
2、ready:異步操作已經完成
3、timeout:異步操作超時
可以使用future的wait()、wait_for()、wait_untill()來獲取任務的完成狀態
1、wait()阻塞調用
2、wait()阻塞一個time_out時間
async異步調用函數的使用
async(launch,func,args)函數有三個參數,分別是啟動方式、任務函數,參數列表
啟動策略有三種方式
1、launch::deferred : 延遲調用異步函數,延遲到future對象調用get()或者wait()的時候才執行func();如果不調用get()或者wait(),func()不會執行。
2、launch::async :強制這個異步任務在一個新線程上執行,這意味着,系統必須要創建出一個新線程來運行func(),新線程創建失敗拋出異常
3、launch::async| launch::deferred : 由系統自行決定選擇那種啟動方式
func的類型可以是函數指針、函數對象、lambda表達式
std::async與std::thread的區別
std::async()與std::thread()最明顯的不同,就是async並不一定創建新的線程
std::thread() 如果系統資源緊張,那么可能創建線程失敗,整個程序可能崩潰。
std::thread()創建線程的方式,如果線程返回值,你想拿到這個值也不容易;
std::async()創建異步任務,可能創建也可能不創建線程;並且async調用方式很容易拿到線程入口函數的返回值。
#include<iostream> #include<thread> #include<string> #include<vector> #include<list> #include<mutex> #include<future> using namespace std; int mythread() //線程入口函數 { cout << "mythread start " << "threadid= " << this_thread::get_id() << endl; //打印線程id chrono::milliseconds dura(5000); //定一個5秒的時間 this_thread::sleep_for(dura); //休息一定時常 cout << "mythread end " << "threadid= " << this_thread::get_id() << endl; //打印線程id return 5; } int main() { future<int> result = async(mythread);//默認方式啟動線程、無參數傳遞 //獲取異步任務的完成狀態 //future_status是一個枚舉類型的值,wait()和wait_for()返回該枚舉類型的值 //wait()會阻塞調用線程,直到異步任務完成取消阻塞 //wait_for(time_out)會阻塞一段時間,在time_out時間內返回並結束阻塞 while (1) { future_status status = result.wait_for(std::chrono::seconds(1));//每一秒鍾輪詢一次狀態 //異步操作還沒被調用 if (status == future_status::deferred) { //調用開始 cout << result.get() << endl; } //異步操作超時 else if (status == future_status::timeout) { cout << "超時:表示線程還沒執行完!" << endl; } //異步調用結束 else if (status == future_status::ready) { //表示線程成功返回 cout << "線程成功執行完畢,返回!" << endl; cout << result.get() << endl; break; } } cout << "Finish!" << endl; system("pause"); return 0; }