所有,我一直在考慮的工作,多線程的大型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(...)
代碼包裝成可重複使用的方法,上面顯示的是明智之舉。
所以,'WorkbookView'必須從UI線程訪問,但是'IWorksheet'和'IRange'可以從另一個線程使用?你不能把這兩個對象傳給'GenerateStage()'嗎? – svick
'workbookViewAsync = workbookView'將*不*創建一個副本,它只會將*引用*複製到另一個變量中。但新變量仍然會指向舊對象。 – svick
第一篇文章是一個合理的建議,但要在工作表或IRange上執行操作,您必須在工作簿集或WorkbookView上調用GetLock(),這又意味着要訪問「WorkbookView」,它是在UI線程上創建。 – MoonKnight