Moo*_*ght 7 c# multithreading task-parallel-library async-await .net-4.5
总而言之,我已经获得了多线程大型C#应用程序的工作.要做到这一点,我选择使用async/ await.我清楚地知道使用的IProgress<T>报告进度,以在UI(我们称之为"推"信息发送到UI),但我还需要从UI到"拉"的数据(在我的情况下的SpreadsheetGear工作簿,它包含数据).正是这种双向互动,我想要一些建议......
目前我触发了一个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...
...
}
Run Code Online (Sandbox Code Playgroud)
然后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
}
}
Run Code Online (Sandbox Code Playgroud)
到目前为止,这似乎很好.我现在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...
}
Run Code Online (Sandbox Code Playgroud)
在这种方法中,我需要从UI中提取数据并多次将数据写入UI.对于写作,我可以清楚地使用'progressInfo',但是如何处理来自UI的拉取信息.在这里,我使用了UI线程同步上下文,但这将完成很多次.有没有更好的方法来执行这些操作/我目前的方法有任何缺陷吗?
注意.显然,我会将Task.Factory.StartNew(...)代码包装成一个可重用的方法,上面的内容是明确显示的.
如果您不断地在 UI 和线程池线程之间来回切换,您的代码将会有点混乱。
您基本上有两个选择:让您的“正常”上下文成为线程池线程,其中部分计划到 UI 线程(就像您现在所拥有的那样),或者让您的“正常”上下文成为 UI 线程,其中部分计划到线程池线。
我通常更喜欢后者,因为您可以使用更简单的方法Task.Run而不是Task.Factory.StartNew在特定的TaskScheduler. 但无论哪种方式,代码都会有点混乱。
| 归档时间: |
|
| 查看次数: |
1445 次 |
| 最近记录: |