Penjujukan Tugasan dan Kemasukan Semula: Mengurus Perintah Berjujukan dalam Persekitaran Berbilang Thread
Dalam aplikasi perisian dunia sebenar, adalah perkara biasa untuk menghadapi senario di mana tugas dikendalikan secara berurutan, dan susunan pelaksanaannya adalah kritikal. Penjujukan tugasan menjadi lebih kompleks apabila tugasan mungkin tiba lebih cepat daripada yang boleh diproses, dan ia dimasukkan semula, bermakna ia boleh dilaksanakan serentak dalam diri mereka sendiri.
Pertimbangkan senario berikut:
Secara tradisinya, isu Sync-or-Async boleh diatasi dengan menggunakan kaedah Task.Factory.StartNew dengan parameter TaskScheduler.FromCurrentSynchronizationContext() untuk memaksa pelaksanaan tak segerak. Walau bagaimanapun, pendekatan ini mungkin tidak sesuai jika pengendali arahan direka bentuk untuk melaksanakan secara serentak secara dalaman.
Untuk menangani cabaran ini, kelas tersuai yang dipanggil AsyncOp boleh dilaksanakan. AsyncOp mengendalikan penjujukan tugas dan keperluan kemasukan semula. Berikut ialah versi kemas kini kelas AsyncOp dengan ciri tambahan:
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)); } } }
Versi yang dikemas kini ini menyediakan peningkatan berikut:
Menggunakan kelas AsyncOp yang dikemas kini ini, kod sampel yang disediakan dalam soalan boleh ditulis semula seperti berikut:
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(); } } }
Dalam versi yang dikemas kini ini, tugasan handleAsync terpaksa dijalankan secara tak segerak menggunakan kaedah Task.Delay untuk menunjukkan keupayaan kemasukan semula AsyncOp.
Penyelesaian ini menyediakan cara yang mantap dan cekap untuk mengurus penjujukan tugasan dan kemasukan semula, memastikan bahawa arahan dilaksanakan dalam susunan yang diingini, tanpa mengira kadar ia tiba.
Atas ialah kandungan terperinci Bagaimanakah AsyncOp Boleh Menguruskan Penjujukan Tugasan dan Kemasukan Semula dengan Cekap dalam Persekitaran Berbilang Thread?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!