C#异步并行处理的用法

复制代码
await Task.Run(() =>
{
    Parallel.ForEach(_equips, eq =>
    {
        WriteOneEquipFromDb(eq, lineName, jzName, selectedBatchNo);
    });
});

逐层解析

|----|---------------------------|-------------------|
| 层级 | 组件 | 作用 |
| 1 | `await` | 等待异步操作完成,不阻塞UI线程 |
| 2 | `Task.Run()` | 在线程池线程上执行委托 |
| 3 | `Parallel.ForEach()` | 并行遍历集合,多线程同时处理 |
| 4 | `WriteOneEquipFromDb()` | 实际业务方法(读写PLC+数据库) |

执行流程图

主线程(UI)

↓

await Task.Run() → 创建新线程(线程A)

↓

Parallel.ForEach()

├─ 线程1: WriteOneEquipFromDb(_equips0)

├─ 线程2: WriteOneEquipFromDb(_equips1)

├─ 线程3: WriteOneEquipFromDb(_equips2)

└─ ... 同时执行多个设备

↓

全部完成后返回

↓

继续执行后续代码(OutputInfomation等)

关键特性

1. 双重并行机制

复制代码
// 第一层:Task.Run 把任务放到线程池
Task.Run(() => { ... })  // 避免阻塞UI

// 第二层:Parallel.ForEach 内部再并行
Parallel.ForEach(...)     // 多个设备同时处理

2. 线程安全考虑

WriteOneEquipFromDb 内部使用了 Invoke 更新UI:

复制代码
// 这是正确的做法,因为Parallel.ForEach的线程不是UI线程
Invoke(new Action(() => OutputInfomation(...)));

潜在问题与风险

问题1:PLC连接并发冲突

复制代码
// 危险!多个线程同时连接不同PLC(IP不同,通常安全)
// 但如果 _equips 中有相同IP的设备,会冲突!

private void WriteOneEquipFromDb(Equip eq, ...)
{
    var plc = new SvMitsubishiMC3E();
    plc.Connect(eq.IP, port);  // 每个线程独立连接,通常安全
}

问题2:数据库连接池压力

复制代码
// 每个设备都创建新的数据库连接(通过 _dbHelper)
// 如果设备数量多(>10),可能耗尽连接池

问题3:异常处理不完善

复制代码
// Parallel.ForEach 中一个线程异常,其他线程继续
// 但异常会被聚合抛出,需要正确处理

改进建议

方案A:限制并行度(推荐)

复制代码
await Task.Run(() =>
{
    var options = new ParallelOptions { MaxDegreeOfParallelism = 3 }; // 最多3个并发
    Parallel.ForEach(_equips, options, eq =>
    {
        WriteOneEquipFromDb(eq, lineName, jzName, selectedBatchNo);
    });
});

方案B:使用 async/await 替代 Parallel

复制代码
// 更可控的并发
await Task.Run(async () =>
{
    var tasks = _equips.Select(eq => 
        Task.Run(() => WriteOneEquipFromDb(eq, lineName, jzName, selectedBatchNo))
    );
    await Task.WhenAll(tasks); // 等待全部完成
});

方案C:顺序执行(最安全,但最慢)

复制代码
await Task.Run(() =>
{
    foreach (var eq in _equips) // 不用Parallel
    {
        WriteOneEquipFromDb(eq, lineName, jzName, selectedBatchNo);
    }
});

|----------------|----------------------------------|
| 场景 | 建议方案 |
| 设备少(<5台),不同IP | 当前代码可用 |
| 设备多(>5台),不同IP | 限制 MaxDegreeOfParallelism 为3-4 |
| 设备IP可能重复 | 必须改为顺序执行 |
| 需要精确进度反馈 | 使用 Task.WhenAll + 单独任务跟踪 |

相关推荐
波力海苔夹心脆67515 分钟前
C# 视觉检测实战:PLC 按钮触发 VisionPro 检测,OK 亮灯 / NG 灭灯(西门子 PLC,含界面显示与图片存档)
开发语言·经验分享·c#·自动化·视觉检测·.net
kim1 小时前
一个人 + AI,用 WinForms 搓了个 376KB 的 Windows 便签:便签 / 截图 / 标注 / OCR / 待办全塞进去了
c#
hez20102 小时前
一行代码在 .NET 项目里启用 Satori GC
c#·.net·.net core·gc·clr
宇卿.2 小时前
C#语句:
开发语言·c#
咕白m6252 小时前
使用 C# 将 TIFF 转换为 PDF
前端·c#
JQLvopkk3 小时前
HslCommunication,一个工具测遍所有 PLC
开发语言·人工智能·c#·交互
下页、再停留4 小时前
【C#桌面客户端系列学习-7】数据查询展示
开发语言·c#·visual studio
QQ14220784495 小时前
从 C# WinForms 到 Flask + SQLite:期刊出版 XML 生成器(JATS)重构实践
sqlite·flask·c#
半亩码田5 小时前
C#转Python第4.7篇:logging:Python 的标准日志库
开发语言·python·c#
宝桥南山6 小时前
.NET 11 - 尝试创建一下AGUIServer和AGUIClient(基于新版.NET SDK for AG-UI)
microsoft·ai·微软·c#·aigc·.net