すべて、私は大規模なC#アプリケーションをマルチスレッド化する仕事を与えられました。これを行うために、私はasync
/を使用することを選択しましたawait
。を使用して進行状況をIProgress<T>
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(...)
コードを再利用可能なメソッドにまとめます。上記は簡潔さのために明示的に示されています。