You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#并行计算负载均衡异常:仅单台打印机工作另一台闲置

问题分析与解决方案

核心问题点

  1. Printer类静态Name字段冲突:public static string Name 是静态字段,所有Printer实例共享同一个值。最后创建的HP 1434会覆盖之前的HP 1222,导致所有打印输出都显示这台打印机的名字,看起来另一台处于闲置状态。
  2. Loadbalancer状态不共享:每次实例化Loadbalancer都会新建一对打印机和独立的页数统计变量,多个Loadbalancer之间没有全局负载状态,负载均衡逻辑完全失效。
  3. print方法线程安全实现错误:lock (this) 包裹Task.Run没有实际作用,Task.Run会立刻在新线程执行,lock瞬间释放,无法保证打印过程的原子性,多个任务可能同时在同一台打印机上执行。

修正后的代码实现

1. 修正Printer类

namespace Printer
{
    public class Printer
    {
        // 改为实例字段,每个打印机拥有独立名称
        public string Name { get; }
        // 记录该打印机的总任务页数
        private int _totalPages;
        // 专用锁对象,避免lock(this)的潜在风险
        private readonly object _lockObj = new object();

        public Printer(string name) => Name = name;

        public void Print(int pages)
        {
            lock (_lockObj)
            {
                // 在lock内执行打印逻辑,保证同一打印机的任务串行执行
                for (int i = 0; i < pages; i++)
                {
                    Console.WriteLine($"Printing page {i+1} in printer {Name}");
                    Thread.Sleep(300);
                }
                // 线程安全地更新总页数
                _totalPages += pages;
            }
        }

        // 线程安全的总页数获取方法
        public int GetTotalPages()
        {
            lock (_lockObj)
            {
                return _totalPages;
            }
        }
    }

2. 修正Loadbalancer类

改为单例模式,维护全局共享的打印机和负载状态:

public class LoadBalancer
    {
        // 懒加载单例,保证全局唯一实例
        private static readonly Lazy<LoadBalancer> _instance = new Lazy<LoadBalancer>(() => new LoadBalancer());
        public static LoadBalancer Instance => _instance.Value;

        // 全局共享的打印机实例
        private readonly Printer _p1;
        private readonly Printer _p2;

        private LoadBalancer()
        {
            _p1 = new Printer("HP 1222");
            _p2 = new Printer("HP 1434");
        }

        // 统一的任务提交方法
        public void SubmitPrintJob(int pages)
        {
            int p1Total = _p1.GetTotalPages();
            int p2Total = _p2.GetTotalPages();

            // 按总页数较少的原则分配任务
            if (p1Total <= p2Total)
            {
                Task.Run(() => _p1.Print(pages));
            }
            else
            {
                Task.Run(() => _p2.Print(pages));
            }
        }
    }

3. 修正Main方法

使用同一个LoadBalancer实例提交所有任务:

internal class Program
    {
        static void Main(string[] args)
        {
            var loadBalancer = LoadBalancer.Instance;
            // 提交多个打印任务
            Task.Run(() => loadBalancer.SubmitPrintJob(10));
            Task.Run(() => loadBalancer.SubmitPrintJob(20));
            Task.Run(() => loadBalancer.SubmitPrintJob(30));

            Console.ReadKey();
        }
    }
}

关键改进说明

  • Printer类:去掉静态Name字段,每个实例拥有独立标识;用私有锁对象保证打印任务串行执行和总页数统计的线程安全;直接在lock内处理打印逻辑,避免异步导致的锁失效。
  • LoadBalancer类:采用单例模式保证全局唯一实例,共享同一组打印机;新增SubmitPrintJob方法统一处理任务提交,每次分配都基于两台打印机的实时总页数,实现真正的负载均衡。
  • Main方法:统一使用同一个LoadBalancer实例提交所有任务,确保负载状态全局共享。

内容的提问来源于stack exchange,提问作者Muhammad Yahya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 05:37:06