所有,我一直在考虑的工作,多线程的大型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