Rumah >pembangunan bahagian belakang >C++ >Bagaimanakah AsyncOp Boleh Menguruskan Penjujukan Tugasan dan Kemasukan Semula dengan Cekap dalam Persekitaran Berbilang Thread?

Bagaimanakah AsyncOp Boleh Menguruskan Penjujukan Tugasan dan Kemasukan Semula dengan Cekap dalam Persekitaran Berbilang Thread?

Linda Hamilton
Linda Hamiltonasal
2025-01-04 20:13:49268semak imbas

How Can AsyncOp Efficiently Manage Task Sequencing and Re-Entrancy in Multithreaded Environments?

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:

  1. Tugas pengendali arahan UI boleh diselesaikan secara serentak atau tidak segerak.
  2. Arahan boleh tiba pada kadar yang lebih cepat daripada yang diproses.
  3. Jika tugas yang belum selesai sudah wujud untuk sesuatu arahan, tugasan pengendali arahan baharu hendaklah digilir dan dilaksanakan secara berurutan.
  4. Hasil setiap tugasan baharu mungkin bergantung pada hasil tugasan sebelumnya.

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:

  • Masuk semula : AsyncOp kini menyokong kemasukan semula dengan membenarkan nested tugasan.
  • Keselamatan benang: Kunci digunakan untuk melindungi medan _pending.
  • Batal/Mulakan Semula: Baharu HandleCancelAsync dan Kaedah HandleRestartAsync membolehkan anda membatalkan atau memulakan semula jujukan tugasan dengan anggun.

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!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn