C#并行计算负载均衡异常:仅单台打印机工作另一台闲置
问题分析与解决方案
核心问题点
- Printer类静态Name字段冲突:
public static string Name是静态字段,所有Printer实例共享同一个值。最后创建的HP 1434会覆盖之前的HP 1222,导致所有打印输出都显示这台打印机的名字,看起来另一台处于闲置状态。 - Loadbalancer状态不共享:每次实例化Loadbalancer都会新建一对打印机和独立的页数统计变量,多个Loadbalancer之间没有全局负载状态,负载均衡逻辑完全失效。
- 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
相关产品推荐
相关产品推荐

