タスクの順序付けと再入: マルチスレッド環境での順次コマンドの管理
実際のソフトウェア アプリケーションでは、次のようなシナリオに遭遇するのが一般的です。タスクは順番に処理され、実行順序が重要です。タスクが処理できるより早く到着する可能性があり、タスクがリエントラントである、つまりタスク自体内で同時に実行できる場合、タスクのシーケンスはさらに複雑になります。
次のシナリオを考えてみましょう:
従来、同期または非同期の問題は、Task.Factory.StartNew を使用することで解決できます。メソッドに TaskScheduler.FromCurrentSynchronizationContext() パラメータを指定して非同期実行を強制します。ただし、コマンド ハンドラーが内部で同期的に実行されるように設計されている場合、このアプローチは理想的ではない可能性があります。
この課題に対処するために、AsyncOp というカスタム クラスを実装できます。 AsyncOp は、タスクの順序付けと再入の要件を処理します。追加機能を備えた AsyncOp クラスの更新バージョンを次に示します。
class AsyncOp<T> { private Task<T> _pending = Task.FromResult(default(T)); private readonly object _lock = new object(); public Task<T> CurrentTask => _pending; public Task<T> RunAsync(Func<Task<T>> handler, bool useSynchronizationContext = false) { Task<Task<T>> task = null; lock (_lock) { var pending = _pending; Task<T> wrapper = async () => { // Await the previous task T prevResult = await pending; Console.WriteLine("\nPrevious task result: " + prevResult); // Start and await the handler return await handler(); }; task = new Task<Task<T>>(wrapper); var inner = task.Unwrap(); _pending = inner; } task.RunSynchronously(useSynchronizationContext ? TaskScheduler.FromCurrentSynchronizationContext() : TaskScheduler.Current); return inner; } public async Task HandleCancelAsync() { Task pendingCopy = null; lock (_lock) { pendingCopy = _pending; } // Cancel previous tasks as long as they are not the latest (current) task if (pendingCopy != CurrentTask && pendingCopy != null) await ((Task)pendingCopy).ContinueWith(t => t.Dispose()); } public async Task HandleRestartAsync() { Task pendingCopy = null; lock (_lock) { pendingCopy = _pending; if (pendingCopy.IsCompleted && pendingCopy != null) _pending = Task.FromResult(default(T)); } } }
この更新バージョンでは、次の機能強化が提供されます。
この更新された AsyncOp クラスを使用すると、質問で提供されているサンプル コードを書き直すことができます次のように:
using System; using System.Threading.Tasks; namespace ConsoleApp { class Program { static async Task Main(string[] args) { var asyncOp = new AsyncOp<int>(); Func<int, Task<int>> handleAsync = async (arg) => { Console.WriteLine("This task arg: " + arg); // Delay the execution await Task.Delay(arg); return await Task.FromResult(arg); }; Console.WriteLine("Test #1..."); asyncOp.RunAsync(() => handleAsync(1000)); asyncOp.RunAsync(() => handleAsync(900)); asyncOp.RunAsync(() => handleAsync(800)); await asyncOp.CurrentTask; Console.WriteLine("\nPress any key to continue to test #2..."); Console.ReadLine(); asyncOp.RunAsync(() => { var handle100Task = handleAsync(100); asyncOp.RunAsync(() => handleAsync(200), true); return handle100Task; }); await asyncOp.CurrentTask; Console.WriteLine("\nPress any key to exit..."); Console.ReadKey(); } } }
この更新されたバージョンでは、handleAsync タスクが強制的に実行されます。 Task.Delay メソッドを非同期的に使用して、AsyncOp の再入機能を実証します。
このソリューションは、タスクの順序付けと再入を管理する堅牢かつ効率的な方法を提供し、コマンドが到着速度に関係なく、希望の順序で実行されます。
以上がAsyncOp はマルチスレッド環境でタスクのシーケンスと再入を効率的に管理するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。