详解.NET异步
??? 在說到異步前,先來理一下幾個(gè)容易混淆的概念,并行、多線程、異步。
??? 并行,一般指并行計(jì)算,是說同一時(shí)刻有多條指令同時(shí)被執(zhí)行,這些指令可能執(zhí)行于同一CPU的多核上,或者多個(gè)CPU上,或者多個(gè)物理主機(jī)甚至多個(gè)網(wǎng)絡(luò)中。
??? 多線程,一般指同一進(jìn)程中多個(gè)線程(包含其數(shù)據(jù)結(jié)構(gòu)、上下文與代碼片段)協(xié)作運(yùn)行。在多核計(jì)算機(jī)中多個(gè)線程將有機(jī)會(huì)同時(shí)運(yùn)行于多個(gè)核上,如果線程中進(jìn)行的是計(jì)算,則行成并行計(jì)算。
??? 異步,與同步相對(duì)應(yīng),是指呼叫另一操作后,不等待其結(jié)果,繼續(xù)執(zhí)行之后的操作,若之后沒有其他操作,當(dāng) 前線程將進(jìn)入睡眠狀態(tài),而CPU時(shí)間將有機(jī)會(huì)切至其他線程。在異步操作完成后通過回調(diào)函數(shù)的方式獲取通知與結(jié)果。異步的實(shí)現(xiàn)方式有多種,如多線程與完成端 口。多線程將異步操作放入另一線程中運(yùn)行,通過輪詢或回調(diào)方法得到完成通知;完成端口,由操作系統(tǒng)接管異步操作的調(diào)度,通過硬件中斷,在完成時(shí)觸發(fā)回調(diào)方 法,此方式不需要占用額外線程。
?
??? 本文討論.NET下的異步,以及其進(jìn)化過程中出現(xiàn)的多種異步模式。
?
??? 首先看一下兩段需要花較長(zhǎng)時(shí)間運(yùn)行的代碼在同步方式下的情形。???
public class ProgramClass{
public static void Main()
{
using (var fs = new FileStream("Data.dat", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, 4096))
{
fs.Write(new byte[100], 0, 100);
}
DoSomething();
Console.WriteLine("END");
}
static string DoSomething()
{
Thread.Sleep(2000);
return "Finished";
}
}
????同步方式運(yùn)行時(shí),所有操作會(huì)順序執(zhí)行,當(dāng)某方法被阻塞時(shí),線程即進(jìn)入阻塞狀態(tài)。該情形下,CPU時(shí)間無(wú)法得到充分利用,當(dāng)前線程長(zhǎng)時(shí)間處于阻塞狀態(tài),任務(wù)總時(shí)間長(zhǎng)。
???
???
??? 開始異步化
?
??? 為提高CPU使用率,從而減少任務(wù)時(shí)間,采用多線程方式實(shí)現(xiàn)異步調(diào)用。
public class ProgramClass{
public static void Main()
{
Thread writeThread = new Thread(new ThreadStart(WriteWapper));
Thread doSomethingThread = new Thread(new ParameterizedThreadStart(DoSomethingWapper));
ClosureClass closure = new ClosureClass();
writeThread.Start();
doSomethingThread.Start(closure);//閉包對(duì)象,用于變量穿越
writeThread.Join();
doSomethingThread.Join();
Console.WriteLine(closure.Result);
}
//將方法包裝成適于線程調(diào)用的簽名
private static void WriteWapper()
{
using (var fs = new FileStream("Data.dat", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, 4096))
{
fs.Write(new byte[100], 0, 100);
}
}
//將方法包裝成適于線程調(diào)用的簽名
static void DoSomethingWapper(object state)
{
ClosureClass closure = state as ClosureClass;
var result = DoSomething();
if (closure != null)
{
closure.Result = result;
}
}
static string DoSomething()
{
Thread.Sleep(2000);
return "Finished";
}
//閉包輔助類,用于存儲(chǔ)在方法間傳遞內(nèi)部變量與參數(shù)
class ClosureClass
{
//存儲(chǔ)方法返回值
public string Result { get; set; }
}
}
??? 利用多線程將耗時(shí)操作放入其他線程中進(jìn)行處理,主線程繼續(xù)做自己的事(本例中,主線程進(jìn)行等待其他線程完成)。從而減少任務(wù)處理時(shí)間。
??? 【注意】本例中,write與dosomething操作內(nèi)部均有線程等待,在單核中依然可以通過操作系統(tǒng)的線程切換提高CPU使用率,但是如果操作是需 要大量CPU計(jì)算,則在單核情況下并不一定能夠提高CPU使用率,并且可能增加線程調(diào)試的開銷,因此單核情況下此種方式不適合用于密集型運(yùn)算。
??? 【提示】對(duì)于線程的入口方法,我們往往會(huì)對(duì)其進(jìn)行包裝,形成一致的方法簽名、處理異常、攔截請(qǐng)求等。在本例中,由于被調(diào)用的方法有輸入與輸出,困此采用輔助對(duì)象進(jìn)行傳遞,在C#2開始引入的閉包,采用類似的原理實(shí)現(xiàn),從而減少大量的代碼,并提高程序可讀性。
public class ProgramClass{
public static void Main()
{
string result = null;
Thread writeThread = new Thread(new ThreadStart(WriteWapper));
Thread doSomethingThread = new Thread(new ThreadStart(() =>
{
result = DoSomething();//跨方法訪問臨時(shí)變量,形成閉包
}));
writeThread.Start();
doSomethingThread.Start();
writeThread.Join();
doSomethingThread.Join();
Console.WriteLine(result);
}
//將方法包裝成適于線程調(diào)用的簽名
private static void WriteWapper()
{
using (var fs = new FileStream("Data.dat", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, 4096))
{
fs.Write(new byte[100], 0, 100);
}
}
static string DoSomething()
{
Thread.Sleep(2000);
return "Finished";
}
}
??? 開啟一個(gè)新線程將帶來可觀的開銷,因此我們希望能夠重用線程,在.NET中,可以采用線程池達(dá)到這一目的,同時(shí)簡(jiǎn)化線程的操作。
public class ProgramClass{
public static void Main()
{
string result = null;
AutoResetEvent resetEvent = new AutoResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback(state =>
{
result = DoSomething();
resetEvent.Set();
}));
resetEvent.WaitOne();
Console.WriteLine(result);
}
static string DoSomething()
{
Thread.Sleep(2000);
return "Finished";
}
}
??? 由于線程池中,我們無(wú)法對(duì)線程進(jìn)行更為細(xì)致的操作,為得到操作完成的通知,我們需要在包裝方法中,在操作完成后加入適當(dāng)?shù)拇a,本例中我們采用ResetEvent進(jìn)行線程的同步。
??? 【注意】在ASP.NET中,所有的WEB線程均運(yùn)行于線程池,因此線程池中的線程是非常寶貴的資源,耗盡線程池中的線程將可能引起所有的請(qǐng)求進(jìn)入等待隊(duì)列,從而無(wú)法提供服務(wù),在ASP.NET中的線程池操作應(yīng)該更為謹(jǐn)慎。
?
?
??? 完成端口與異步模型
?
????到這里為止,都是采用多線程的方式手動(dòng)實(shí)現(xiàn)了異步,正如前面所說,多線程不適用于單核密集運(yùn)算,在非密集運(yùn)算下也會(huì)產(chǎn)生線 程調(diào)度的開銷,在需要大量線程的應(yīng)用中會(huì)浪費(fèi)寶貴資源。考察需要阻塞等待的場(chǎng)景,往往是與系統(tǒng)外部數(shù)據(jù)交換有關(guān),如大量?jī)?nèi)存數(shù)據(jù)的復(fù)制、讀寫磁盤文件、訪 問網(wǎng)絡(luò)等,這種情況下,在硬件完成操作前CPU無(wú)能為力,因此只能等待,更完美的方案是發(fā)出指令后不進(jìn)入等待,當(dāng)操作完畢后通過某種方式得到通知并執(zhí)行相 關(guān)代碼,稱為完成端口。
??? 完成端口編程復(fù)雜,并且需要操作系統(tǒng)支持,使用中需要先判斷是否支持,再采用不同的方式去實(shí)現(xiàn),并且實(shí)現(xiàn)的方法多樣,在異步使用頻繁的今天,為簡(jiǎn)化異步操作,往往會(huì)制訂一種統(tǒng)一的異步模型,并且這類模型也在不斷進(jìn)化中。
??? 在介紹異步模型時(shí),我們會(huì)用不同的方法先將一個(gè)普通方法異步調(diào)用,再調(diào)用類庫(kù)中提供的異步方法,然后實(shí)現(xiàn)一個(gè)自己的異步方法,最后將多個(gè)異步方法按順序調(diào)用包裝成新的異步方法。
??? 在早期的.NET中,采用 BeginXXX/EndXXX 方式實(shí)現(xiàn)異步。
??? 對(duì)于普通的方法,可以采用委托的 BeginInvoke / EndInvoke 實(shí)現(xiàn)異步化。
???
public class ProgramClass{
public static void Main()
{
string result = null;
var doSomgthingDelegate = new Func<string>(DoSomething);
var asyncResult = doSomgthingDelegate.BeginInvoke(new AsyncCallback(aresult =>
{
result = doSomgthingDelegate.EndInvoke(aresult);
}), null);
asyncResult.AsyncWaitHandle.WaitOne();
Console.WriteLine(result);
}
static string DoSomething()
{
Thread.Sleep(2000);
return "Finished";
}
}
????委托的異步內(nèi)部采用線程池實(shí)現(xiàn)。
??? 有些類庫(kù)中的方法,實(shí)現(xiàn)了異步版本。
public static void Main(){
using (var fs = new FileStream("Data.dat", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, 4096
, FileOptions.Asynchronous))
{
fs.Write(new byte[100], 0, 100);
var asyncResult = fs.BeginWrite(new byte[100], 0, 100, new AsyncCallback(aresult => {
fs.EndWrite(aresult);//執(zhí)行完畢后的回調(diào)方法
}), null);
asyncResult.AsyncWaitHandle.WaitOne();
}
}
??? 對(duì)于類庫(kù)的方法的異步版本,內(nèi)部會(huì)進(jìn)行判斷決定采用何種方式實(shí)現(xiàn)。
??? 【注意】對(duì)于FileStream,必須加上FileOptions.Asynchronous才會(huì)有機(jī)會(huì)使用完成端口。
??? 現(xiàn)在我們可以根據(jù)這個(gè)模型來實(shí)現(xiàn)自己的異步方法。
public class ProgramClass{
public static void Main()
{
DoSomeThing();
var result = BeginDoSomeThing(1, new AsyncCallback(aresult =>
{
ProgramClass.EndDoSomeThing(aresult);
}), null);
result.AsyncWaitHandle.WaitOne();
}
//同步版本
public static string DoSomeThing()
{
Thread.Sleep(2000);
return "Finished";
}
//異步版本開始
public static IAsyncResult BeginDoSomeThing(int arg1, AsyncCallback callback, object state)
{
var asyncResult = new DoSomethingAsyncResult(callback, state);
Timer timer = null;
timer = new Timer(new TimerCallback(s =>
{
timer.Dispose();
asyncResult.SetComplete("Finished");
}), state, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2));
return asyncResult;
}
//異步版本結(jié)束
public static string EndDoSomeThing(IAsyncResult asyncResult)
{
DoSomethingAsyncResult result = asyncResult as DoSomethingAsyncResult;
if (result != null)
{
return result.Result;
}
return null;
}
//AsyncResult對(duì)象
public class DoSomethingAsyncResult : IAsyncResult
{
private AsyncCallback _asyncCallback;
private AutoResetEvent _asyncWaitHandle;
public DoSomethingAsyncResult(AsyncCallback asyncCallback, object state)
{
AsyncState = state;
_asyncCallback = asyncCallback;
_asyncWaitHandle = new AutoResetEvent(false);
}
//設(shè)置結(jié)果
public void SetComplete(string result)
{
Result = result;
IsCompleted = true;
if (_asyncCallback != null)
{
_asyncCallback(this);
}
_asyncWaitHandle.Set();
}
public string Result
{
get;
private set;
}
public object AsyncState
{
get;
private set;
}
public WaitHandle AsyncWaitHandle
{
get { return _asyncWaitHandle; }
}
public bool CompletedSynchronously
{
get { return false; }
}
public bool IsCompleted
{
get;
private set;
}
}
}
??? 本例中,采用定時(shí)器觸發(fā)完成動(dòng)作,實(shí)際中,可以在需要的時(shí)候觸發(fā)完成。
??? 對(duì)于BeginXXX/EndXXX模式,調(diào)用BeginXXX表示開始一個(gè)異步方法,前面的參數(shù)表示方法所需的參數(shù)(可無(wú)),倒數(shù)第二個(gè)參數(shù)為回調(diào)方法 (可空),最后一個(gè)參數(shù)用于穿越整個(gè)過程的相關(guān)對(duì)象(可空)。返回的IAsyncResult存儲(chǔ)了異步方法的相關(guān)狀態(tài)信息,一般來說我們自己的異步方法 需要一個(gè)實(shí)現(xiàn)了該接口的類,類中包含了回調(diào)方法、等待對(duì)象、相關(guān)參數(shù)與結(jié)果等。
??? 異步方法的協(xié)作有三種方法,第一種,通過輪詢 IsCompleted 屬性,直到為true時(shí),觸發(fā)完成動(dòng)作。
??? 第二種,通過回調(diào)方法,當(dāng)異步方法完成時(shí),由異步方法調(diào)用回調(diào)方法。
???
??? 第三種,通過WaitHandler等待異步方法完成,當(dāng)異步方法完成時(shí),由異步方法發(fā)出完成信號(hào),使等待結(jié)束。
???
??? 當(dāng)我們需要將多個(gè)異步方法包裝成一個(gè)異步方法時(shí),方法內(nèi)部將充斥著大量的回調(diào)方法。
??? 類似于這樣:
public static IAsyncResult BeginDoSomeThing(int arg1, AsyncCallback callback, object state){
var asyncResult = new DoSomethingAsyncResult(callback, state);
Timer timer = null;
timer = new Timer(new TimerCallback(s =>
{
timer.Dispose();
using (var fs = new FileStream("Data.dat", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, 4096, FileOptions.Asynchronous))
{
var writeresult = fs.BeginWrite(new byte[100], 0, 100, new AsyncCallback(wresult =>
{
fs.EndWrite(wresult);
asyncResult.SetComplete("Finished");
}), null);
}
}), state, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2));
return asyncResult;
}
??? 呼~幸好還有匿名方法與閉包,否則將是一件多么恐怖的事啊。???
?
??? 新的異步模型
?
?
??? 我們清醒的看到,當(dāng)需要多個(gè)異步方法需要協(xié)作時(shí),代碼將顯得十分復(fù)雜,無(wú)法表現(xiàn)清晰的邏輯,于是,我們需要一個(gè)更好的異步模型。
??? 從.NET4開始,引入了新的異步模型。
??? 首先引入一個(gè)新概念:Task。
??? Task代表一個(gè)可以被執(zhí)行的任務(wù),我們可以讓他運(yùn)行,關(guān)聯(lián)其他任務(wù),等待他,獲取他的結(jié)果。值得注意的是,這里的Task可以是一個(gè)異步的任務(wù),也可以 是同步的任務(wù),在沒有特別說明的情況下都指異步任務(wù)。而返回一個(gè)Task對(duì)象的方法,我們一般認(rèn)為這是一個(gè)異步方法。new Task或者Task.Run將生成一個(gè)在線程池中運(yùn)行的異步任務(wù)。
??? 的按照慣例,我們看一下如何把一個(gè)普通的方法異步執(zhí)行。
public static void Main(){
var t1 = Task<int>.Run(() =>
{
Thread.Sleep(2000);
return 100;
}).ContinueWith(new Action<Task<int>>(t =>
{
Console.WriteLine(t.Result);
}));
t1.Wait();
}
??? 對(duì)于類庫(kù)中提供的異步方法,也有了新版本,XXXAsync。
public static void Main(){
using (var fs = new FileStream("Data.dat", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, 4096,
FileOptions.Asynchronous))
{
var task = fs.WriteAsync(new byte[100], 0, 100)
.ContinueWith(new Action<Task>(t => {
Console.WriteLine("Finished");
}));
task.Wait();
}
}
??? 我們不再關(guān)心如何去開始,何時(shí)會(huì)結(jié)束,一切變成了一些有關(guān)或無(wú)關(guān)的任務(wù)。
??? 讓我們自己寫一個(gè)異步方法吧。
public static Task<string> DoSomethingAsync(int value){
return Task<string>.Run(() =>
{
Thread.Sleep(2000);
return value.ToString();
}); ;
}
??? 好吧,你肯定是以我在偷懶,為什么不像BeginXXX/EndXXX一樣從底層開始實(shí)現(xiàn)一個(gè)呢,那是因?yàn)門ask的封裝比較嚴(yán),我們無(wú)法直接對(duì)其擴(kuò)展。 為了達(dá)到獲取一個(gè)Task,在需要的時(shí)候設(shè)置完成與結(jié)果,可以借助 AsyncTaskMethodBuilder 來實(shí)現(xiàn)。
public class ProgramClass{
public static void Main()
{
var task = ProcessAsync();
task.Wait();
var r = task.Result;
}
static Task<string> ProcessAsync()
{
//輔助工具
AsyncTaskMethodBuilder<string> builder = AsyncTaskMethodBuilder<string>.Create();
Timer timer = null;
timer = new Timer(s =>
{
timer.Dispose();
builder.SetResult("Finished");//在需要時(shí)設(shè)置結(jié)果
}, null, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2));
return builder.Task;//獲取需要的Task
}
}
??? 類似的方法,我們封裝一個(gè)由多個(gè)異步方法組合成的異步方法。
???
{
public static void Main()
{
var task = ProcessAsync();
task.Wait();
var r = task.Result;
}
static Task<string> ProcessAsync()
{
//輔助工具
AsyncTaskMethodBuilder<string> builder = AsyncTaskMethodBuilder<string>.Create();
DoSomethingAync1().GetAwaiter().OnCompleted(() =>
{
DoSomethingAync2().GetAwaiter().OnCompleted(() =>
{
DoSomethingAync2().GetAwaiter().OnCompleted(() =>
{
builder.SetResult("Finished");
});
});
});
return builder.Task;//獲取需要的Task
}
static Task<string> DoSomethingAync1() { ... }
static Task<string> DoSomethingAync2() { ... }
static Task<string> DoSomethingAync3() { ... }
}
??? 組合異步方法調(diào)用后,按順序調(diào)用第一個(gè)異步方法,緊接著,產(chǎn)生需要的結(jié)果Task后返回。異步方法完成時(shí)回調(diào)指定的方法,并按順序繼續(xù)調(diào)用,所有方法完成后,把運(yùn)行的最終結(jié)果設(shè)置給結(jié)果Task,那么整個(gè)任務(wù)即完成。??
??
??? 如果異步方法有回返值,那么組合的異步方法看上去會(huì)復(fù)雜一點(diǎn)。
static Task<string> ProcessAsync(){
//輔助工具
AsyncTaskMethodBuilder<string> builder = AsyncTaskMethodBuilder<string>.Create();
string r1, r2, r3;//用于存儲(chǔ)每一個(gè)任務(wù)的結(jié)構(gòu)
var awaitor1 = DoSomethingAync1().GetAwaiter();
awaitor1.OnCompleted(() =>
{
r1 = awaitor1.GetResult();
var awaitor2 = DoSomethingAync2().GetAwaiter();
awaitor2.OnCompleted(() =>
{
r2 = awaitor2.GetResult();
var awaitor3 = DoSomethingAync3().GetAwaiter();
awaitor3.OnCompleted(() =>
{
r3 = awaitor3.GetResult();
builder.SetResult(r1 + r2 + r3);//計(jì)算最終結(jié)構(gòu)并設(shè)置結(jié)果
});
});
});
return builder.Task;//獲取需要的Task
}
??? 代碼雖然復(fù)雜了一點(diǎn),但還能夠接受,這里的每個(gè)異步方法的返回值需要臨時(shí)變量來存儲(chǔ),包括每個(gè)異步方法的TaskAwaiter對(duì)象,需要跨越多個(gè)方法, 這里將形成閉包,使得這些對(duì)象無(wú)法盡快釋放,同時(shí),每一個(gè)異步方法都將附加一個(gè)OnComplete回訪方法的委托對(duì)象,這些都是使用上述方法的代價(jià),這 些代價(jià)在理論上是可以被優(yōu)化的,但是帶來的是更為復(fù)雜的代碼結(jié)果,暫且放下吧,因?yàn)?#xff0c;解決方案就在后面。
?
?
??? 重口味語(yǔ)法糖
?
?
? 在C#5中,添加了 async/await 關(guān)鍵字,使得上面遺留的問題得以解決,而且重點(diǎn)是,用起來非常簡(jiǎn)單!
??? 上面的代碼在C#5時(shí)代可以寫成下面的樣子:
static async Task<string> ProcessAsync(){
var r1 = await DoSomethingAync1();
var r2 = await DoSomethingAync2();
var r3 = await DoSomethingAync3();
return r1 + r2 + r3;
}
??? 是不是震驚了。
??? 他幾乎和同步方法寫法一致。程序的邏輯完全沒有因?yàn)楫惒蕉騺y,并且減少了代碼量,這就是語(yǔ)法糖的魅力。
??? 語(yǔ)法糖的背后隱藏了不為人知的內(nèi)部實(shí)現(xiàn),特別重口味語(yǔ)法糖,我們需要知道他背后的實(shí)現(xiàn),才不致于消化不良。
????先看一下語(yǔ)法,async關(guān)鍵字告訴編譯器,對(duì)本方法使用語(yǔ)法糖,對(duì)于這類方法只能返回 void/Task/Task<T>,返回void/Task代表異步方法不返回任何結(jié)果,返回void在調(diào)用方看來是一個(gè)同步方法,沒有機(jī) 會(huì)獲取異步回調(diào)。返回Task<T>代表返回結(jié)果為T的異步方法,在該方法內(nèi)部,可以直接返回類型為T的結(jié)果。在返回結(jié)果前可以使用 await關(guān)鍵字調(diào)用其他異步方法,并且可以直接獲取該異步方法的返回值。無(wú)需處理任何Task相關(guān)的內(nèi)容。當(dāng)async方法內(nèi)部沒有任何await時(shí), 該方法效果與同步相同,僅僅是簡(jiǎn)單包裝后Task而已。
??? 該方法的執(zhí)行順序與前面我們自己實(shí)現(xiàn)的相同,內(nèi)部實(shí)現(xiàn)也有一些類似,同樣采用AsyncTaskBuilder構(gòu)建Task對(duì)象,在我們自己實(shí)現(xiàn)的方法 中,在方法內(nèi)部(一個(gè)或多個(gè)匿名方法與閉包對(duì)象)實(shí)現(xiàn)多個(gè)異步方法的調(diào)度,而async/await語(yǔ)法糖則采用一個(gè)狀態(tài)機(jī)對(duì)象作為媒介進(jìn)行多個(gè)異步方法 的調(diào)度。
??
??? 編譯后,async異步方法將執(zhí)行過程委托給狀態(tài)機(jī),自己則向AsyncTaskBuilder獲取Task返回,狀態(tài)機(jī)內(nèi)部存儲(chǔ)方法內(nèi)部參與計(jì)算的臨時(shí) 變量(閉包),維護(hù)當(dāng)前執(zhí)行狀態(tài),-1代表開始與中間狀態(tài),-2代表結(jié)束,0-n代表正在執(zhí)行第n個(gè)異步方法,狀態(tài)機(jī)的MoveNext方法按順序去調(diào)用 其他的異步方法,如異步方法已執(zhí)行完畢則繼續(xù)往下執(zhí)行,如未完畢,則設(shè)置當(dāng)前狀態(tài),存儲(chǔ)任務(wù)的Awaiter對(duì)象,并關(guān)聯(lián)完成動(dòng)作(狀態(tài)機(jī)方法本身的單例 委托對(duì)象)后結(jié)束,當(dāng)異步方法執(zhí)行完畢,繼續(xù)調(diào)用狀態(tài)機(jī)MoveNext方法,按照狀態(tài)找到執(zhí)行入口點(diǎn),找到上次執(zhí)行的Awaiter對(duì)象,并獲取執(zhí)行結(jié) 果,然后繼續(xù)找到下一個(gè)異步方法執(zhí)行,重復(fù)以上的步驟,如果異步方法間有其他代碼,照本執(zhí)行,當(dāng)所有異步方法與內(nèi)部代碼執(zhí)行完畢后,通過 AsyncTaskBuilder向異步方法的結(jié)果Task設(shè)置結(jié)果值,該Task即完成。
???
??? 從編譯后的結(jié)果可以看到,這里不再存在閉包對(duì)象與多個(gè)回調(diào)方法及其委托對(duì)象,全部合在狀態(tài)機(jī)對(duì)象當(dāng)中,而每一次異步方法調(diào)用后的Awaiter對(duì)象也可以 在異步方法完成后釋放引用,在狀態(tài)機(jī)對(duì)象中根據(jù)簽名的種類提供必要的字段位置,狀態(tài)機(jī)本身也是結(jié)構(gòu)體,最大限度上減少了空間的開銷與GC的壓力,而所有的 這一切,編譯器通通搞定,而程序員,只需要關(guān)注邏輯的順序與結(jié)果的處理即可。
本文轉(zhuǎn)載自http://www.cnblogs.com/wisdomqq/archive/2012/03/29/2417723.html
轉(zhuǎn)載于:https://www.cnblogs.com/wsion/archive/2013/03/20/2971335.html
總結(jié)
- 上一篇: android NDK 在Ubuntu1
- 下一篇: 管理Java类文件