我正在閱讀Eric Lippert關於C#5新異步功能的博客article series。在那裏,他使用了一個方法的示例,從遠程位置獲取文檔,並且一旦檢索到,就將其歸檔到存儲驅動器中。這是他使用的代碼:C#5.0中的異步:Eric Lippert的示例如何工作?
async Task<long> ArchiveDocumentsAsync(List<Url> urls)
{
long count = 0;
Task archive = null;
for(int i = 0; i < urls.Count; ++i)
{
var document = await FetchAsync(urls[i]);
count += document.Length;
if (archive != null)
await archive;
archive = ArchiveAsync(document);
}
return count;
}
現在設想獲取文檔非常快。所以第一個文件被提取。之後,它開始被存檔,而第二個文檔正在被抓取。現在想象第二個文檔已被提取,並且第一個文檔仍被歸檔。這段代碼是否會開始提取第三個文檔或等到第一個文檔被存檔?
正如埃裏克在其文章中說,這段代碼被編譯器轉換成這樣:
Task<long> ArchiveDocuments(List<Url> urls)
{
var taskBuilder = AsyncMethodBuilder<long>.Create();
State state = State.Start;
TaskAwaiter<Document> fetchAwaiter = null;
TaskAwaiter archiveAwaiter = null;
int i;
long count = 0;
Task archive = null;
Document document;
Action archiveDocuments =() =>
{
switch(state)
{
case State.Start: goto Start;
case State.AfterFetch: goto AfterFetch;
case State.AfterArchive: goto AfterArchive;
}
Start:
for(i = 0; i < urls.Count; ++i)
{
fetchAwaiter = FetchAsync(urls[i]).GetAwaiter();
state = State.AfterFetch;
if (fetchAwaiter.BeginAwait(archiveDocuments))
return;
AfterFetch:
document = fetchAwaiter.EndAwait();
count += document.Length;
if (archive != null)
{
archiveAwaiter = archive.GetAwaiter();
state = State.AfterArchive;
//----> interesting part! <-----
if (archiveAwaiter.BeginAwait(archiveDocuments))
return; //Returns if archive is still working => Fetching of next document not done
AfterArchive:
archiveAwaiter.EndAwait();
}
archive = ArchiveAsync(document);
}
taskBuilder.SetResult(count);
return;
};
archiveDocuments();
return taskBuilder.Task;
}
其他問題:
如果停止執行,將有可能繼續讀取文件?如果是,如何?
好吧,讓我們假設你從本地驅動器獲取文件並將它們上傳到遠程位置...... – Simon