Bagaimana cara menerapkan asinkroni dengan benar dalam kode ini?

pemrograman


Ada entitas “tugas”. Ini memiliki properti berikut:
– memuat pada pelaksana – int (dari 1 hingga 5);
– waktu eksekusi (detik) – int.
Tugas-tugas ini diterima oleh distributor (penyeimbang beban). Ada juga pelaksana yang menerima tugas dari penyeimbang beban dan menjalankannya. Pelaksana memiliki parameter berikut:
– jumlah maksimum tugas yang dijalankan secara bersamaan – int;
– total beban maksimum – int.

Pelaksana menjalankan tugas untuk waktu “waktu eksekusi (detik)”, yang dijelaskan dalam properti tugas. Penyeimbang beban mengambil tugas dari antrean dan mendistribusikannya di antara pelaksana. Tugas hanya dapat didistribusikan kepada pelaksana yang mempunyai cadangan kapasitas yang diperlukan dan cadangan slot kosong untuk tugas. Distribusinya harus merata. Tidak boleh satu pemain terisi penuh dan sisanya beristirahat.

– harus berupa tampilan visual di konsol yang menunjukkan beban kerja masing-masing pelaksana (jumlah tugas yang dilakukan, berapa banyak sumber daya yang ditempati/bebas) dan jumlah tugas dalam antrian;
– harus dilaksanakan secara asinkron (semua pelaksana harus bekerja secara paralel);
– di awal program, antrian tugas harus dibuat, yang selanjutnya akan dibaca oleh penyeimbang dan dikirim ke pelaksana

Masalah saya adalah penggunaan asinkron yang salah. Para pelaksana harus bekerja secara paralel. Bagaimana cara menerapkannya dengan benar?

Apa yang saya coba:

C#
public class TaskEntity
{
    public int Load { get; set; }
    public int ExecutionTime { get; set; }

    public TaskEntity(int load, int executionTime)
    {
        Load = load;
        ExecutionTime = executionTime;
    }
}

public class Executor
{
    public int MaxTasks { get; set; }
    public int MaxLoad { get; set; }
    public int CurrentLoad { get; set; }
    public List<TaskEntity> CurrentTasks { get; set; }
    public Executor(int maxTasks, int maxLoad)
    {
        MaxTasks = maxTasks;
        MaxLoad = maxLoad;
        CurrentLoad = 0;
        CurrentTasks = new List<TaskEntity>();
    }
}

public class LoadBalancer
{
    private readonly List<Executor> Executors;
    private readonly Queue<TaskEntity> TaskQueue;

    public LoadBalancer(List<Executor> executors)
    {
        Executors = executors;
        TaskQueue = new Queue<TaskEntity>();
    }

    public async Task StartAsync()
    {
        while (true)
        {
            if (TaskQueue.Count > 0)
            {
                var task = TaskQueue.Dequeue();
                var availableExecutor = GetAvailableExecutor(task);

                if (availableExecutor != null)
                {
                    await ExecuteTaskAsync(task, availableExecutor);
                }
            }

            DisplayLoadStatus();
            await Task.Delay(1000); 
        }
    }

    public void EnqueueTask(TaskEntity task)
    {
        TaskQueue.Enqueue(task);
    }

    private Executor GetAvailableExecutor(TaskEntity task)
    {
        return Executors.Find(e => e.CurrentLoad + task.Load <= e.MaxLoad &&
                                     e.CurrentTasks.Count < e.MaxTasks);
    }

    private async Task ExecuteTaskAsync(TaskEntity task, Executor executor)
    {
        executor.CurrentLoad += task.Load;
        executor.CurrentTasks.Add(task);

        await Task.Delay(task.ExecutionTime * 1000);

        executor.CurrentLoad -= task.Load;
        if (executor.CurrentTasks.Contains(task))
        {
            executor.CurrentTasks.Remove(task);
        }
    }

    private void DisplayLoadStatus()
    {
        Console.Clear();
        foreach (var executor in Executors)
        {
            Console.WriteLine($"Executor {Executors.IndexOf(executor) + 1}:");
            Console.WriteLine($"  - Current Workload: {executor.CurrentLoad}/{executor.MaxLoad}");
            Console.WriteLine($"  - Concurrent Tasks: {executor.CurrentTasks.Count}/{executor.MaxTasks}");
            Console.WriteLine();
        }

        Console.WriteLine($"Task Queue Size: {TaskQueue.Count}");
    }



static async Task Main()
{
    var executorCount = 3; 
    var executors = new List<Executor>();

    for (int i = 0; i < executorCount; i++)
    {
        executors.Add(new Executor(maxTasks: 2, maxLoad: 10));
    }

    var loadBalancer = new LoadBalancer(executors);

    var loadBalancerTask = loadBalancer.StartAsync();

    var random = new Random();
    for (int i = 0; i < 10; i++)
    {
        var task = new TaskEntity(load: random.Next(1, 6), executionTime: random.Next(1, 6));

        loadBalancer.EnqueueTask(task);
        await Task.Delay(1000); 
    }

    await loadBalancerTask;
}

Solusi 1

Saat Anda ingin beberapa tugas dijalankan secara inline, Anda perlu menyimpan referensi ke setiap tugas dan tidak menunggunya. Menunggu setiap tugas akan menyebabkannya berjalan secara berurutan.

Berikut adalah contoh sederhana menjalankan pekerjaan secara inline.

1. Pekerjaan:

C#
class Job
{
    public string Id { get; }
    public int Runtime { get; }

    public Job(string id, int runtime)
    {
        Id = id;
        Runtime = runtime;
    }

    public async Task<Job> ExecuteAsync()
    {
        await Task.Yield();

        int elapsed = 0;
        TimeSpan delay = TimeSpan.FromSeconds(1);

        while (elapsed < Runtime)
        {
            Console.WriteLine($"{Id} ping {elapsed++} of {Runtime}");
            await Task.Delay(delay);
        }

        Console.WriteLine($"{Id} ping {elapsed++} of {Runtime}");
        return this;
    }
}

Manajer:

C#
var tasks = new List<Task<Job>>();

var rand = new Random();

for (int i = 0; i < 10; i++)
{
    Job job = new Job($"Task {i}", rand.Next(3, 6));

    tasks.Add(job.ExecuteAsync());
}

while (true)
{
    Task.WaitAny(tasks.ToArray());

    foreach (Task<Job> task in tasks.Where(
        x => x.IsCompleted || x.IsCanceled || x.IsFaulted).ToList())
    {
        var completedJob = await task;
        Console.WriteLine($"!! Job{completedJob.Id} completed");
        tasks.Remove(task);
    }

    if (tasks.Count == 0)
        break;
}

Ini akan memberi Anda konsep untuk membantu Anda memperbarui kode Anda.

コメント

タイトルとURLをコピーしました