2014-09-11 91 views
0

我有一個方法void getInformation(),它調用5個其他方法,每個方法都從數據庫獲取一些數據。它需要大約1秒,直到收集所有數據並返回到getInformation(),並且因爲我認爲我應該在後臺收集數據。我的問題是:我可以只製作getInformation()async,以便在其他方法正在收集信息時不會阻止用戶界面,或者是否必須製作其他所有方法async瞭解異步方法

private void button_Click(object sender, EventArgs e) 
{ 
    await getContactInformation(); 
} 

public async Task getContactInformation() 
{ 
    this.data.Add(collectData1()); 
    this.data.Add(collectData2()); 
    this.data.Add(collectData3()); 
    this.data.Add(collectData4()); 
    this.data.Add(collectData5()); 
} 
+0

看看這個[教程](http://www.dotnetperls.com/async) – 2014-09-11 10:37:12

+1

看看這些問答:https://stackoverflow.com/questions/14177891/can-somebody-please-explain- async-await,https://stackoverflow.com/questions/10960998/how-different-async-programming-is-from-threads和https://stackoverflow.com/questions/14455293/async-and-await – Dirk 2014-09-11 10:43:42

回答

2

首先,async的理想情況是使用「異步一路」。在這種情況下,你的代碼應該是這樣的:

private async void button_Click(object sender, EventArgs e) 
{ 
    await getContactInformationAsync(); 
} 

public async Task getContactInformationAsync() 
{ 
    this.data.Add(await collectData1Async()); 
    this.data.Add(await collectData2Async()); 
    this.data.Add(await collectData3Async()); 
    this.data.Add(await collectData4Async()); 
    this.data.Add(await collectData5Async()); 
} 

需要注意的是現代數據庫API,如實體框架6,ADO.NET時,SQLite等,都可以用它來實現collectDataNAsync方法異步的API 。這是理想的async方案,因爲它可以最大限度地減少線程浪費並保持UI的良好響應。

但是,如果你想要更多的是「速戰速決」,那麼你就可以推(同步)調用開了一個後臺線程,然後把這樣的背景下異步工作,因爲這樣的:

private async void button_Click(object sender, EventArgs e) 
{ 
    await Task.Run(() => getContactInformation()); 
} 

public void getContactInformation() 
{ 
    this.data.Add(collectData1()); 
    this.data.Add(collectData2()); 
    this.data.Add(collectData3()); 
    this.data.Add(collectData4()); 
    this.data.Add(collectData5()); 
} 

這將以線程池線程爲代價解決您的直接問題(釋放UI線程)。這不是理想但它會工作。

+0

我使用的API不提供異步方法,但感謝您的建議 – user2414460 2014-09-11 12:59:30

2

一般來說,我會建議所有IO將採取關閉UI線程,但在使每一個單獨的呼叫async沒有意義的。

有關async對數據庫IO阻塞線程調用的影響的指導,我發現這個非常明確和有用的建議。

http://blogs.msdn.com/b/rickandy/archive/2009/11/14/should-my-database-calls-be-asynchronous.aspx

+0

我認爲在這種情況下,每次調用'async'都不是正確的解決方案,並且感謝您的鏈接 – user2414460 2014-09-11 12:00:01

2

號你的方法的身體已經使用的await,否則你會得到一個警告。

夠簡單。

總結你的方法體...

await Task.Run(()=>{ 
// do your thing 
}); 
+0

您的意思是在'// do your thing'應該是數據收集調用,我會好嗎? – user2414460 2014-09-11 12:01:49

+0

是的。將其替換爲您的普通同步代碼以使其在單獨的線程上運行。 – kidshaw 2014-09-11 14:34:19

+0

感謝@DanielKelley的編輯。從內存寫入,可以使用factory.startnew代替運行。 – kidshaw 2014-09-11 14:36:05

1

目的異步任務是讓它在後臺執行不鎖定主線程,比如做一個DownloadFileAsync。 基本思想是你有一個獨立的線程池,異步執行任務。使用它時。然而,該對象承諾它會在某個時間執行操作並在請求時給出結果。這意味着當你請求結果並且沒有完成時它會阻塞,否則在線程池中執行。

異步和同步之間唯一的區別是我們可以在異步方法啓動後執行某些操作(如編寫消息)。它避免了阻止控制流。聲明繼續如常。 異步和等待是一種代碼模式 - 它們允許方法異步運行。它們使得使用線程的代碼更易於閱讀。這反過來又使得代碼不太容易出現缺陷。

http://blogs.msdn.com/b/cdndevs/archive/2013/12/18/c-async-and-await-why-do-we-need-them-part-1.aspx

How and When to use `async` and `await`

最後

程序都充滿了不立即返回的方法。有時,從網絡來看,外部速度下降是原因,而不是處理器的使用。使用異步和等待,我們異步運行方法 - 線程是可選的。

1

我可以只做getInformation()異步,以便在其他方法正在收集信息時不阻止用戶界面,或者是否必須使每個其他方法異步?

後者。當你去async它是「異步一路」,這意味着你使async方法調用一直到你的堆棧頂部。對於IO綁定操作,不需要使用後臺線程,因爲現在大多數API都暴露了XXXAsync真正異步的方法調用,這意味着您的UI消息循環可以在IO請求執行時自由處理其他消息。

但需要注意的一點很重要,即標記方法async不足以使其異步。您實際上必須爲await進行異步操作,例如您的數據庫方法調用。如果沒有異步API調用數據庫,您將無法進行異步。

在你的情況下,getContactInformation會讓編譯器忽略警告,說你有一個未被等待的異步方法。事實上,如果你await getInformation(),你將會完全同步運行。

+0

但是,如果我想使數據收集調用「異步」,我將不得不改變我的整個項目。這段代碼只是想知道如何得到這個解決方案 – user2414460 2014-09-11 12:05:53

+0

解決方案是讓你的數據收集調用「異步」。這是主要的一點。如果你的數據庫調用是同步的,你希望如何使它們異步? – 2014-09-11 12:21:28

+0

我希望有一個解決方案,我不需要改變所有方法體和頭文件,就像'BackgroundClass.doInBackground(methodCall)',這使得UI響應,但仍然執行被調用的方法。 – user2414460 2014-09-11 12:26:52