我們先來看下面的乙個小示例:乙個winfrom程式,介面上有乙個按鈕,有兩個非同步方法,點選按鈕呼叫兩個非同步方法,彈出執行順序,**如下:
usingsystem;
using
system.threading;
using
system.threading.tasks;
using
system.windows.forms;
namespace
tpldemosln
//////
按鈕點選事件
/// ///
///private
async
void btnstart_click(object
sender, eventargs e)
//////
非同步方法f1
/// ///
private taskf1async());}
//////
非同步方法f2
/// ///
private taskf2async());}
}}
在上面的**中,task.run()是用來把乙個**段包裝為task的方法,run中委託的**體就是非同步任務執行的邏輯,最後return返回值。
執行程式,可以得到如下的輸出順序:
f1 start->f1 run->i1=f1->f2 start->f2 run->i2=f2。
我們對按鈕事件進行修改,修改為下面的**,在看看執行順序:
//////按鈕點選事件
//////
///private
async
void btnstart_click(object
sender, eventargs e)
再次執行程式,檢視輸出順序:
f1 start->f2 start->f1 run->i1=f1->f2 run->i2=f2。
可以看出兩次的執行順序不一致。這是什麼原因呢?
這是因為並不是到了await才開始執行task非同步任務,執行到tasktask1=f1async()這句**的時候,f1async非同步任務就開始執行了。同理,執行到下一句**就開始執行f2async非同步任務了。await是為了保證執行到這裡的時候非同步任務一定執行完。執行到await的時候,如果非同步任務還沒有執行,那麼就等待非同步任務執行完。如果非同步任務已經執行完了,那麼就直接獲取非同步任務的返回值。
我們上面解釋的原因是否正確呢?我們可以做下面的乙個實驗,來驗證上面說的原因,我們把按鈕事件裡面的await注釋掉,看看非同步方法還會不會執行,**如下:
//////按鈕點選事件
//////
///private
async
void btnstart_click(object
sender, eventargs e)
執行程式,發現非同步方法還是會執行,這就說明我們上面解釋的原因是正確的。感興趣的可以使用reflector反編譯檢視內部實現的原理,主要是movenext()方法內部。
我們可以得到下面的結論:
只要方法是task型別的返回值,都可以用await來等待呼叫獲取返回值。
如果乙個返回task型別的方法被標記了async,那麼只要方法內部直接return t這個型別的例項就可以了。
乙個返回task型別的方法如果沒有被標記為async,那麼需要方法內部直接return乙個task的例項。
上面說的第二點看下面的**
//////方法標記為async 直接返回乙個int型別的數值即可
//////
private
async taskf3async()
上面的第三點可以看下面的**:
//////方法沒有被標記為async,直接返回乙個task
//////
private taskf4async()
);}
我們做一些總結:
1、如果方法內部有await,則方法必須標記為async。await和async是成對出現的,只有await沒有async程式會報錯。只有async沒有await,程式會按照同步方法執行。
2、asp.net mvc中的action方法和winform中的事件處理方法都可以標記為async,控制台的main()方法不能被標記為async。對於不能標記為async的方法怎麼辦呢?我們可以使用result屬性來獲取值,看下面**:
不建議使用這種方式,這樣體現不出非同步帶來的好處,而且使用result屬性,有可能會帶來上下文切換造成的死鎖。下面我們來看看建立task的方法。
1、如果返回值就是乙個立即可以隨手得到的值,那麼就用task.fromresult()。看下面**:
static tasktestasync());
//簡便寫法
return task.fromresult(3
);}
3、task.factory.fromasync()會把iasyncresult轉換為task,這樣apm風格的api也可以用await來呼叫。
4、編寫非同步方法的簡化寫法。如果方法宣告為async,那麼可以直接return具體的值,不用在建立task,由編譯器建立task,看下面的**:
staticasync tasktest2async()
);
//下面是簡化寫法,直接返回
return6;
}
tpl模板引擎和使用
tpl.php namespace tpl class tpl class tpl 如果快取檔案不為空,則設定,為空時為預設值 if empty cache dir 如果過期時間不為空,則設定,為空時為預設值 if empty lifetime 對外公開的方法 param string name p...
this指標探秘
參考 深度探索c 物件模型對this的描述是,this是乙個函式引數 float manitude3d const point3d this float point3d manitude3d const 這兩種方式是等價的,編譯器在內部將後者轉化為前者,因此 obj.magintude 變成了mag...
C 使用任務並行庫 TPL
tpl task parallel library 任務並行庫 tpl 是 system.threading和 system.threading.tasks 命名空間中的一組公共型別和 api。tpl 的目的是通過簡化將並行和併發新增到應用程式的過程來提高開發人員的工作效率。使用執行緒池可以減少並行...