总而言之,我被赋予了对大型 C# 应用程序进行多线程处理的工作。为此,我选择使用async
/ await
。我很清楚使用向IProgress<T>
UI报告进度(让我们将此称为向 UI 的“推送”信息),但我还需要从 UI 中“提取”数据(在我的例子中是一个 SpreadsheetGear 工作簿,其中包含数据)。正是这种双向互动,我想要一些建议......
目前我触发点击事件开始处理,代码结构如下:
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(...)
代码包装成一个可重用的方法,为了简洁起见,上面明确显示。