7

所有,我一直在考慮的工作,多線程的大型C#應用程序。爲此,我選擇使用async/await。我深知使用IProgress<T>的報告進度的UI(我們稱之爲「推」信息發送到UI),但我還需要從UI到「拉」的數據(在我的情況下的SpreadsheetGear工作簿,其中包含數據)。這是我想了一些建議這種雙向互動...多線程大型C#應用程序中使用異步/等待

目前我火click事件處理開始,並且該代碼具有以下結構:

CancellationTokenSource cancelSource; 
private async void SomeButton_Click(object sender, EventArgs e) 
{ 
    // Set up progress reporting. 
    IProgress<CostEngine.ProgressInfo> progressIndicator = 
     new Progress<CostEngine.ProgressInfo>(); 

    // Set up cancellation support, and UI scheduler. 
    cancelSource = new CancellationTokenSource(); 
    CancellationToken token = cancelSource.Token; 
    TaskScheduler UIScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 

    // Run the script processor async. 
    CostEngine.ScriptProcessor script = new CostEngine.ScriptProcessor(this); 
    await script.ProcessScriptAsync(doc, progressIndicator, token, UIScheduler); 

    // Do stuff in continuation... 
    ... 
} 

然後在ProcessScriptAsync,我有以下幾種:

public async Task ProcessScriptAsync(
    SpreadsheetGear.Windows.Forms.WorkbookView workbookView, 
    IProgress<ProgressInfo> progressInfo, 
    CancellationToken token, 
    TaskScheduler UIScheduler) 
{ 
    // This is still on the UI thread. 
    // Here do some checks on the script workbook on the UI thread. 
    try 
    { 
     workbookView.GetLock(); 
     // Now perform tests... 
    } 
    finally { workbookView.ReleaseLock(); } 

    // Set the main processor off on a background thread-pool thread using await. 
    Task<bool> generateStageTask = null; 
    generateStageTask = Task.Factory.StartNew<bool>(() => 
     GenerateStage(workbookView, 
      progressInfo, 
      token, 
      UIScheduler)); 
    bool bGenerationSuccess = await generateStageTask; 

    // Automatic continuation back on UI thread. 
    if (!bGenerationSuccess) { // Do stuff... } 
    else { 
    // Do other stuff 
    } 
} 

這個,到目前爲止,似乎很好。這個問題我現在是在方法GenerateStage,這是現在在後臺線程池線程

private bool GenerateStage(
    SpreadsheetGear.WorkbookView workbookView, 
    IProgress<ProgressInfo> progressInfo, 
    CancellationToken token, 
    TaskScheduler scheduler) 
{ 
    ... 
    // Get the required data using the relevant synchronisation context. 
    SpreadsheetGear.IWorksheet worksheet = null; 
    SpreadsheetGear.IRange range = null; 
    Task task = Task.Factory.StartNew(() => 
    { 
     worksheet = workbookView.ActiveWorksheet; 
     range = worksheet.UsedRange; 
    }, CancellationToken.None, 
     TaskCreationOptions.None, 
     scheduler); 
    try 
    { 
     task.Wait(); 
    } 
    finally 
    { 
     task.Dispose(); 
    } 

    // Now perform operations with 'worksheet'/'range' on the thread-pool thread... 
} 

運行在這個方法中,我需要從UI提取數據和寫入數據到UI多次。對於寫作,我可以清楚地使用'progressInfo',但是如何處理UI中的拉取信息。在這裏,我已經使用了UI線程同步上下文,但是這會做很多次。 有沒有更好的方法來執行這些操作/我目前的方法中是否有任何缺陷?

注。顯然,我會將Task.Factory.StartNew(...)代碼包裝成可重複使用的方法,上面顯示的是明智之舉。

+1

所以,'WorkbookView'必須從UI線程訪問,但是'IWorksheet'和'IRange'可以從另一個線程使用?你不能把這兩個對象傳給'GenerateStage()'嗎? – svick

+1

'workbookViewAsync = workbookView'將*不*創建一個副本,它只會將*引用*複製到另一個變量中。但新變量仍然會指向舊對象。 – svick

+0

第一篇文章是一個合理的建議,但要在工作表或IRange上執行操作,您必須在工作簿集或WorkbookView上調用GetLock(),這又意味着要訪問「WorkbookView」,它是在UI線程上創建。 – MoonKnight

回答

2

如果你不斷地來回UI和線程池中的線程之間,你的代碼將是一個有點凌亂。你基本上有兩個選擇:讓你的「正常」上下文成爲線程池線程,部分調度到UI線程(就像你現在這樣做),或者讓你的「正常」上下文成爲部分調度的UI線程到一個線程池線程。

我通常更喜歡後者,因爲您可以在一個特定的TaskScheduler上使用更簡單的Task.Run而不是Task.Factory.StartNew。但無論如何,代碼會有點混亂。

+0

我也不完全相信,我正在做的是最好的方法,但我真的不能看到另一個。代碼很老很複雜 - 爲了支持多線程而進行重新設計,不僅看起來很不理智(因爲代碼編寫得很好),但在這種情況下,我不明白它對我有何幫助。我主要關心的是我爲了從用戶界面中提取數據而轉離的「任務」數量。清楚地產生這些線程將有一個不可避免的開銷 - 什麼樣的開銷,我不知道呢......謝謝你的時間。 – MoonKnight

0

我沒有使用SpreadsheetGear工作簿,但我想它有一個事件機制,您可以用它來爲您存儲相關數據在自定義對象中,您可以從UISynchronizationContext的外部訪問此對象避免強烈限制工作簿UI控件的方式。這將允許你避免阻塞UI線程與

Task task = Task.Factory.StartNew(() => 
{ 
    worksheet = workbookView.ActiveWorksheet; 
    range = worksheet.UsedRange; 
}, CancellationToken.None, 
    TaskCreationOptions.None, 
    scheduler); 
try 
{ 
    task.Wait(); 
} 
finally 
{ 
    task.Dispose(); 
} 

部分來自GenerateStage方法。

但同樣,我的建議是基於對工作簿的SpreadsheetGear控制一些假設,可以是不正確的。

+1

你可以看[文檔](http://www.spreadsheetgear.com/support/help/spreadsheetgear.net.3.0/SpreadsheetGear~SpreadsheetGear.Windows.Forms.WorkbookView.html)來確認或反駁你的假設。 – svick