簡體   English   中英

C# 理解阻塞的 UI 和異步/等待與 Task.Run 的問題?

[英]C# Understanding trouble with blocked UI and async / await vs. Task.Run?

我正在嘗試做一些與 UI 線程分離的異步 I/O 工作。 我在某處讀到:

  • 1) 對於 CPU 密集型代碼,您等待使用 Task.Run 方法在后台線程上啟動的操作。 比如計算素數
  • 2) 對於 I/O 綁定代碼,您等待一個在異步方法中返回 Task 或 Task 的操作。 如等待網絡或數據庫

所以我這樣做了:

// in windows form UI
private async void btnImport_Click(object sender, EventArgs e) {
    // [...]
    List<DataRow> rows = await importer.ImportDataAsync(123, 456);
    // [...]
}

// in Importer.ImportDataAsync:
public async Task<List<DataRow>> ImportDataAsync(int parent, int child, CancellationToken token = default(CancellationToken)) {

    // [...]
    List<DataRow> list = await RealImportFromDB(parent, child);
    return list;
    // [...]
}


public List<DataRow> RealImportFromDB(int p, int c) {

    List<DataRow> rowList;
    // here fetch the rows from DB over slow network
    // and return the row list
    return rowList;
}

使用這種方法,UI 被阻止。 如果我像這樣調用 RealImportFromDB(...)

List<DataRow> l = await Task.Run(() => RealImportFromDB(parent, child));

用戶界面沒有被阻止,但這與恕我直言上面的第 2) 點沖突。

我哪里做錯了?

最好的問候,亞歷克斯

public List<DataRow> RealImportFromDB(int p, int c)是對數據庫的阻塞調用,因此要異步執行它,您使用了#1,您將調用包裝在Task.Run ,這將釋放Ui 線程如預期

使用這種方法,UI 被阻止。 如果我調用 RealImportFromDB(...)

由於該方法不適用於異步調用,因此它不會返回TaskTask<T> ,這是進行異步調用的常見要求

您的代碼await RealImportFromDB(parent, child)不正確,這是一個編譯錯誤,因為您只能等待調用,它實現了GetAwaiter()內部檢查( thisthis ),最常見的情況是返回TaskTask<T> ,還有其他類型

讓我們試着理解你的兩個陳述:

1) 對於 CPU 密集型代碼,您等待使用 Task.Run 方法在后台線程上啟動的操作。 比如計算素數

這就是你目前正在做的,通常是在客戶端完成以釋放 Ui 線程,而處理發生在后台,但這仍然會使用一個線程池線程來執行,這不像 Ui 線程那么重要,但是還是系統資源

2) 對於 I/O 綁定代碼,您等待一個在異步方法中返回 Task 或 Task 的操作。 如等待網絡或數據庫

為了實現這一點,你需要一個方法,默認情況下是 Async 並返回一個TaskTask<T> ,這些方法是所有數據框架的一部分,對於現在的每個同步方法都有一個相應的異步方法來啟動異步執行,它們是真正的 IO 調用,他們不使用線程,因為處理不在同一個進程中,它跨越網絡/進程邊界,所以調用線程不需要等待,它只需要回來選擇結果,當它到達時(任何線程池線程,不需要調度線程)。 這些方法在內部使用TaskCompletionSource<T>何時使用 TaskCompletionSource ),它具有在網絡調用完成時通知調用者的機制

要實現這一點,您需要一個方法,默認情況下它是 Async 並返回一個 Task 或 Task

非常感謝,這是我的麻煩。 我的RealImportFromDB(...)方法不是異步方法,因為它處理的是似乎還沒有准備好進行異步調用的較舊的專有庫。

這些都是我的thougths:從等待結果ImportDataAsync(...)被稱為內的所有內容(如RealImportFromDB(...)從UI線程出動。 可以這么說: ImportDataAsync(...)所有內容都封裝/運行在第二個非阻塞線程中。

@others:是的,您說得對,我的代碼中的示例甚至無法編譯。 擺弄了很多,所以代碼示例沒有顯示所有更改的內容,抱歉:-}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM