Làm cách nào để triển khai tính không đồng bộ chính xác trong mã này?

lập trình


Có một “nhiệm vụ” thực thể. Nó có các tính chất sau:
– tải vào bộ thực thi – int (từ 1 đến 5);
– thời gian thực hiện (giây) – int.
Những nhiệm vụ này được nhà phân phối (cân bằng tải) nhận. Ngoài ra còn có những người thực thi nhận nhiệm vụ từ bộ cân bằng tải và thực thi chúng. Người thực thi có các tham số sau:
– số lượng tác vụ được thực hiện đồng thời tối đa – int;
– tổng tải tối đa – int.

Người thực thi thực thi tác vụ trong khoảng thời gian “thời gian thực hiện (giây)”, được mô tả trong thuộc tính tác vụ. Bộ cân bằng tải nhận nhiệm vụ từ hàng đợi và phân phối chúng giữa những người thực thi. Nhiệm vụ chỉ có thể được phân phối cho những người thực thi có dự trữ năng lực cần thiết và dự trữ các vị trí trống cho các nhiệm vụ. Sự phân phối phải càng đồng đều càng tốt. Không nên để một người biểu diễn đã tải đầy đủ và những người còn lại đang nghỉ ngơi.

– phải là chế độ xem trực quan trong bảng điều khiển hiển thị khối lượng công việc của từng người thực thi (số lượng tác vụ được thực hiện, số lượng tài nguyên bị chiếm dụng/miễn phí) và số lượng tác vụ trong hàng đợi;
– phải được triển khai không đồng bộ (tất cả người thi hành phải làm việc song song);
– khi bắt đầu chương trình, một hàng nhiệm vụ sẽ được tạo, hàng đợi này sẽ được bộ cân bằng đọc thêm và gửi đến người thực thi

Vấn đề của tôi là việc sử dụng không đồng bộ không chính xác. Người thực thi nên làm việc song song. Làm thế nào để thực hiện nó một cách chính xác?

Những gì tôi đã thử:

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

Giải pháp 1

Khi muốn nhiều tác vụ chạy nội tuyến, bạn cần giữ tham chiếu đến từng tác vụ và không chờ đợi nó. Việc chờ đợi từng tác vụ sẽ khiến chúng chạy tuần tự.

Đây là một ví dụ đơn giản về chạy công việc nội tuyến.

1. Công việc:

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

Người quản lý:

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

Điều này sẽ cung cấp cho bạn khái niệm để giúp bạn cập nhật mã của mình.

コメント

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