タスクの順序付けと再入
タスクが処理よりも早く到着する可能性があり、以前の結果に依存する可能性があるシナリオでは、タスクの順序付けが重要になります。この課題は、再入可能性が必要な場合にさらに悪化します。
問題ステートメント
UI コマンド ハンドラーは、コマンドを同期または非同期で処理する場合があります。コマンドは処理速度を超える速度で到着する可能性があり、キューイングと逐次処理が必要になります。それぞれの新しいタスクの結果は、その先行タスクに依存する可能性があります。わかりやすくするためにキャンセルは除外されていますが、再入はサポートされている必要があります。
初期アプローチ
基本的なコンソール アプリでは、AsyncOp クラスがタスクのシーケンスを管理します。各タスクは前のタスクの継続として扱われ、依存関係が確実に満たされるようにします。ただし、再入性が導入されると、ロジックが機能しなくなります。
同期ソリューション
この問題に対処するために、最初にタスクをスケジュールせずに手動でタスクを構築します。代わりに、「Task.Factory.StartNew」を使用してタスクを同期的に実行し、ラッパー タスクの準備ができるまでタスクが実行されないようにします。これにより、シーケンスが確実に維持されます。
コード実装
class AsyncOp<T> { Task<T> _pending = Task.FromResult(default(T)); public Task<T> CurrentTask => _pending; public Task<T> RunAsync(Func<Task<T>> handler, bool useSynchronizationContext = false) { var pending = _pending; var wrapper = async () => { var prevResult = await pending; Console.WriteLine($"\nprev task result: {prevResult}"); return await handler(); }; var task = new Task<Task<T>>(wrapper); var inner = task.Unwrap(); _pending = inner; task.RunSynchronously(useSynchronizationContext ? TaskScheduler.FromCurrentSynchronizationContext() : TaskScheduler.Current); return inner; } }
更新Output
Test #1... prev task result: 0 this task arg: 1000 prev task result: 1000 this task arg: 900 prev task result: 900 this task arg: 800 Press any key to continue to test #2... prev task result: 800 this task arg: 100 prev task result: 100 this task arg: 200
Extensions
このアプローチでは、共有状態を保護するロックを実装することで、スレッド セーフなどの追加の改善が可能になります。さらに、タスクの中断を処理するために、キャンセル/再起動ロジックを組み込むことができます。
以上が非同期操作で再入可能でタスクのシーケンスを維持するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。