Comment implémenter correctement l’asynchronie dans ce code ?

la programmation


Il existe une entité « tâche ». Il possède les propriétés suivantes :
– charge sur l’exécuteur – int (de 1 à 5) ;
– temps d’exécution (sec.) – int.
Ces tâches sont reçues par le distributeur (load balancer). Il existe également des exécuteurs qui reçoivent des tâches de l’équilibreur de charge et les exécutent. Les exécuteurs ont les paramètres suivants :
– nombre maximum de tâches exécutées simultanément – int ;
– charge totale maximale – int.

L’exécuteur exécute la tâche pendant la durée « durée d’exécution (sec.) », qui est décrite dans les propriétés de la tâche. L’équilibreur de charge prend les tâches de la file d’attente et les répartit entre les exécuteurs. Les tâches ne peuvent être distribuées qu’aux exécuteurs qui disposent des réserves de capacité nécessaires et d’une réserve d’emplacements libres pour les tâches. La répartition doit être la plus égale possible. Il ne faut pas qu’un artiste soit complètement chargé et que les autres se reposent.

– devrait être une vue visuelle dans la console montrant la charge de travail de chaque exécuteur (nombre de tâches effectuées, combien de ressources sont occupées/libres) et le nombre de tâches dans la file d’attente ;
– doit être implémenté de manière asynchrone (tous les exécuteurs doivent travailler en parallèle) ;
– au début du programme, une file d’attente de tâches doit être créée, qui sera ensuite lue par l’équilibreur et envoyée aux exécuteurs

Mon problème est l’utilisation incorrecte de l’asynchronie. Les exécuteurs testamentaires doivent travailler en parallèle. Comment le mettre en œuvre correctement ?

Ce que j’ai essayé :

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;
}

Solution 1

Lorsque vous souhaitez que plusieurs tâches s’exécutent en ligne, vous devez conserver une référence à chaque tâche et ne pas l’attendre. En attendant chaque tâche, elles s’exécuteront séquentiellement.

Voici un exemple simple d’exécution de tâches en ligne.

1. Le travail :

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;
    }
}

Le directeur:

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;
}

Cela devrait vous donner le concept pour vous aider à mettre à jour votre code.

コメント

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