寫第一篇《await使用中的阻塞和并發(fā)》的時(shí)候還自信滿滿,覺得寫的真不錯(cuò),結(jié)果漏洞百出……
更正第二篇《await使用中的阻塞和并發(fā)(二)》的時(shí)候覺得這回不會(huì)再錯(cuò)了……
結(jié)果我正在寫第三篇,而且連篇名都不敢延用了……
首先完善第二篇對(duì)Foreach(Action<T>)的拆解,用很厲害的小兄弟geelaw的話說就是“是用另一個(gè)方法返回λ表達(dá)式創(chuàng)建的委托,并未把λ表達(dá)式換成方法。”慚愧啊,在小兄弟的指點(diǎn)下,修改代碼如下,在Foreach(Action)這個(gè)話題上算是圓滿了:
public void AwaitFuncTaskListNoLambda() { var funcList = new List<Func<Task>>() { Delay3000Async, Delay2000Async, Delay1000Async }; //funcList.ForEach(async _ => await _()); //funcList.ForEach(AwaitAction()); //foreach (var func in funcList) //{ // AwaitAction()(func); //} Action<Func<Task>> L = this.Xxx; foreach (var func in funcList) { L(func); } } async void Xxx(Func<Task> ft) { await ft(); } public Action<Func<Task>> AwaitAction() { return async _ => await _(); } 接下來的文字是本篇的重點(diǎn),來自redjackwang菊苣的指點(diǎn),他指出了我第二篇中仍存在的誤區(qū)和錯(cuò)誤。下面讓我們來領(lǐng)略一下大牛的風(fēng)采。首先從上篇我給出的結(jié)論入手:
第一點(diǎn)需要指出這里的替代僅僅是寫法的變化,async方法內(nèi)部具體實(shí)現(xiàn)可能仍使用Thread等多線程技術(shù)來實(shí)現(xiàn)。這里需要明確async/await僅是一個(gè)異步的寫法,而Thread/BackgroundWorker和Task是多線程。
關(guān)于第二點(diǎn),有兩位菊苣分別提出異議。redjackwang的原話是“await并不會(huì)阻塞任何線程。await只是把當(dāng)前方法狀態(tài)保存并立即返回,不管是主線程還是后臺(tái)線程都不會(huì)阻塞,而是在完成時(shí)call一個(gè)回調(diào)。”胖胖的韋恩卑鄙是這么說的:“說await是主動(dòng)阻塞問題很大。那叫做響應(yīng)式休眠?”
至于第三點(diǎn),那是MSDN坑我,redjackwang大人竟然從MSDN上找到了更詳細(xì)的答案來證明我給出的鏈接是錯(cuò)誤的。在此一定要共享出來給各位,不要被我上篇錯(cuò)誤的結(jié)論誤導(dǎo)了,正確的表述如下:
Tasks created byits publicconstructors are referred to as “cold” tasks, in that they begin their life cycle in the non-scheduled TaskStatus.Created state, and it’s not until Start is called on these instances that they PRogress to being scheduled. All other tasks begin their life cycle in a “hot” state, meaning that their asynchronous execution has already been initiatedand theirTaskStatusis an enumerationvalueotherthan Created.
All tasks returned from TAP methods must be “hot.” If a TAP method internally uses a Task’s constructor to instantiate the task to be returned, the TAP method must call Start on the Task object prior to returning it.Consumers of a TAP methodmaysafelyassume that the returned task is “hot,” andshould not attempt to callStart on any Task returned from a TAP method.Calling Start on a “hot” taskwill result in anInvalidOperationException(this check is handled automatically by the Task class).
為此redjackwang還給出了證明的例子,在這個(gè)例子中,如果注釋掉start方法,Task是不會(huì)自動(dòng)運(yùn)行的。結(jié)論是Task如果是通過構(gòu)造函數(shù)創(chuàng)建的,狀態(tài)是cold的,不會(huì)自動(dòng)運(yùn)行,而前一篇都是通過返回Task的方法創(chuàng)建出來的,狀態(tài)是hot,所以自動(dòng)運(yùn)行了,和在不在async方法中沒有關(guān)系。
private async void Button_Click(object sender, RoutedEventArgs e){ var v = await Foo(); this.Title = v.ToString();} private async Task<long> Foo(){ var t = new Task<long>(() => { long z = 0; for (int i = 0; i < 100000; i++) { z += i; } return z; }); //t.Start(); return await t;}本篇應(yīng)不是最終的結(jié)果,后面如有進(jìn)一步的發(fā)現(xiàn)仍會(huì)更新下去,批判的暴風(fēng)雨還在繼續(xù)……
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注