欢迎各位观众大大浏览阅读我的博客,有空麻烦加一下博客主页关注,谢谢
MES/ERP 多段独立业务多线程并发组件解决方案
你需要的是针对 MES/ERP 场景中连续多段独立不相关的繁复琐碎业务语句,设计支持多线程并行执行的高性能组件,并基于多结构并发模型构建包含可视化界面、后台服务、标准化 API 的完整信息服务中间件方案,核心目标是通过并发执行提升这类琐碎业务的整体处理效率。
本次方案重点解决:独立业务段的线程安全拆分、多结构并发调度、繁复业务的模块化封装,同时保持中间件的易用性、可监控性和可扩展性。
一、核心设计理念
1. 业务场景特征与解决方案映射
| 场景痛点 | 技术解决方案 |
|---|---|
| 多段业务独立无依赖,串行执行效率低 | 业务段原子化封装 + 多线程并行执行 |
| 业务语句繁复琐碎,代码冗余易出错 | 业务段模板化 + 参数化配置 |
| 多结构(产线 / 工单 / 工序)并发冲突 | 分级并发控制 + 资源隔离 |
| 执行状态不可见,问题定位难 | 实时监控 + 日志追踪 + 进度反馈 |
| 外部系统集成复杂 | 标准化 API + 中间件解耦 |
2. 整体架构

3. 核心技术选型
- 多线程框架:.NET Task Parallel Library (TPL) + 自定义线程池
- 并发控制:SemaphoreSlim + 分级锁 + Concurrent 集合
- 业务封装:策略模式 + 模板方法模式 + 原子化业务段
- 通信层 :ASP.NET Web API + SignalR(实时推送)
- 界面层:WinForm(客户端) + DevExpress(增强控件)
- 日志监控:Serilog + ELK(可选) + 实时性能计数器
二、核心组件实现
1. 原子化业务段封装
1.1 业务段基类与通用实现
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
#region 业务段核心枚举
/// <summary>
/// 业务段类型
/// </summary>
public enum BusinessSegmentType
{
DataQuery, // 数据查询
DataUpdate, // 数据更新
ApiCall, // 外部API调用
DeviceCommand, // 设备指令下发
FileOperation, // 文件操作
Calculation // 计算处理
}
/// <summary>
/// 业务段执行状态
/// </summary>
public enum SegmentStatus
{
Pending, // 待执行
Running, // 执行中
Completed, // 完成
Failed, // 失败
Skipped, // 跳过
Cancelled // 取消
}
/// <summary>
/// 并发执行策略
/// </summary>
public enum ConcurrentStrategy
{
Parallel, // 纯并行(无资源竞争)
Sequential, // 串行(有资源依赖)
Batch, // 批量并行(按批次)
Priority // 按优先级并行
}
#endregion
#region 业务段参数模型
/// <summary>
/// 业务段参数基类
/// </summary>
public class SegmentParams
{
/// <summary>
/// 业务段ID
/// </summary>
public string SegmentId { get; set; } = Guid.NewGuid().ToString("N");
/// <summary>
/// 业务段名称
/// </summary>
public string SegmentName { get; set; }
/// <summary>
/// 业务段类型
/// </summary>
public BusinessSegmentType SegmentType { get; set; }
/// <summary>
/// 执行优先级(1-10,1最高)
/// </summary>
public int Priority { get; set; } = 5;
/// <summary>
/// 是否允许跳过(执行失败时)
/// </summary>
public bool AllowSkip { get; set; } = false;
/// <summary>
/// 超时时间(秒)
/// </summary>
public int Timeout { get; set; } = 30;
/// <summary>
/// 重试次数
/// </summary>
public int RetryCount { get; set; } = 0;
/// <summary>
/// 重试间隔(毫秒)
/// </summary>
public int RetryInterval { get; set; } = 1000;
/// <summary>
/// 业务参数(JSON格式)
/// </summary>
public string BusinessParams { get; set; } = "{}";
/// <summary>
/// 关联结构ID(产线/工单/工序ID)
/// </summary>
public string StructureId { get; set; }
/// <summary>
/// 关联结构类型
/// </summary>
public string StructureType { get; set; }
}
/// <summary>
/// 数据查询业务段参数
/// </summary>
public class DataQuerySegmentParams : SegmentParams
{
public DataQuerySegmentParams()
{
SegmentType = BusinessSegmentType.DataQuery;
}
/// <summary>
/// SQL语句
/// </summary>
public string Sql { get; set; }
/// <summary>
/// 查询参数
/// </summary>
public Dictionary<string, object> QueryParams { get; set; } = new Dictionary<string, object>();
/// <summary>
/// 是否返回数据
/// </summary>
public bool ReturnData { get; set; } = true;
}
/// <summary>
/// API调用业务段参数
/// </summary>
public class ApiCallSegmentParams : SegmentParams
{
public ApiCallSegmentParams()
{
SegmentType = BusinessSegmentType.ApiCall;
}
/// <summary>
/// API地址
/// </summary>
public string ApiUrl { get; set; }
/// <summary>
/// 请求方法(GET/POST/PUT/DELETE)
/// </summary>
public string HttpMethod { get; set; } = "POST";
/// <summary>
/// 请求头
/// </summary>
public Dictionary<string, string> Headers { get; set; } = new Dictionary<string, string>();
/// <summary>
/// 请求体
/// </summary>
public string RequestBody { get; set; } = "{}";
}
#endregion
#region 业务段执行结果
/// <summary>
/// 业务段执行结果
/// </summary>
public class SegmentExecutionResult
{
/// <summary>
/// 业务段ID
/// </summary>
public string SegmentId { get; set; }
/// <summary>
/// 执行状态
/// </summary>
public SegmentStatus Status { get; set; }
/// <summary>
/// 执行开始时间
/// </summary>
public DateTime StartTime { get; set; }
/// <summary>
/// 执行结束时间
/// </summary>
public DateTime EndTime { get; set; }
/// <summary>
/// 执行耗时(毫秒)
/// </summary>
public long ExecutionTimeMs => (long)(EndTime - StartTime).TotalMilliseconds;
/// <summary>
/// 执行结果数据
/// </summary>
public string ResultData { get; set; }
/// <summary>
/// 错误信息
/// </summary>
public string ErrorMessage { get; set; }
/// <summary>
/// 实际重试次数
/// </summary>
public int ActualRetryCount { get; set; } = 0;
}
#endregion
#region 业务段执行器(核心)
/// <summary>
/// 业务段执行器基类
/// </summary>
public abstract class BaseSegmentExecutor
{
/// <summary>
/// 业务段参数
/// </summary>
protected readonly SegmentParams _params;
/// <summary>
/// 取消令牌
/// </summary>
protected readonly CancellationToken _cancellationToken;
/// <summary>
/// 进度更新委托
/// </summary>
protected readonly Action<string, int, SegmentStatus> _progressUpdateAction;
/// <summary>
/// 执行结果
/// </summary>
protected SegmentExecutionResult _result = new SegmentExecutionResult();
/// <summary>
/// 构造函数
/// </summary>
/// <param name="segmentParams">业务段参数</param>
/// <param name="cancellationToken">取消令牌</param>
/// <param name="progressUpdateAction">进度更新委托</param>
protected BaseSegmentExecutor(SegmentParams segmentParams,
CancellationToken cancellationToken,
Action<string, int, SegmentStatus> progressUpdateAction = null)
{
_params = segmentParams;
_cancellationToken = cancellationToken;
_progressUpdateAction = progressUpdateAction;
_result.SegmentId = segmentParams.SegmentId;
}
/// <summary>
/// 执行业务段(带重试和超时控制)
/// </summary>
/// <returns></returns>
public async Task<SegmentExecutionResult> ExecuteAsync()
{
_result.StartTime = DateTime.Now;
_progressUpdateAction?.Invoke(_params.SegmentId, 0, SegmentStatus.Running);
try
{
// 超时控制
var timeoutTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(_params.Timeout));
var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(
_cancellationToken, timeoutTokenSource.Token);
// 带重试执行核心逻辑
bool executeSuccess = false;
int retryCount = 0;
while (retryCount <= _params.RetryCount && !executeSuccess)
{
try
{
// 执行核心逻辑
await ExecuteCoreAsync(linkedTokenSource.Token);
executeSuccess = true;
}
catch (OperationCanceledException)
{
_result.Status = SegmentStatus.Cancelled;
_result.ErrorMessage = "执行被取消或超时";
break;
}
catch (Exception ex)
{
retryCount++;
_result.ActualRetryCount = retryCount;
if (retryCount > _params.RetryCount)
{
throw; // 重试次数用尽,抛出异常
}
// 重试间隔
await Task.Delay(_params.RetryInterval, _cancellationToken);
_progressUpdateAction?.Invoke(_params.SegmentId,
(int)(retryCount * 100.0 / (_params.RetryCount + 1)), SegmentStatus.Running);
}
}
if (executeSuccess)
{
_result.Status = SegmentStatus.Completed;
_progressUpdateAction?.Invoke(_params.SegmentId, 100, SegmentStatus.Completed);
}
}
catch (OperationCanceledException)
{
_result.Status = SegmentStatus.Cancelled;
_result.ErrorMessage = "执行被取消";
_progressUpdateAction?.Invoke(_params.SegmentId, 0, SegmentStatus.Cancelled);
}
catch (Exception ex)
{
_result.Status = _params.AllowSkip ? SegmentStatus.Skipped : SegmentStatus.Failed;
_result.ErrorMessage = ex.Message;
_progressUpdateAction?.Invoke(_params.SegmentId, 0, _result.Status);
}
finally
{
_result.EndTime = DateTime.Now;
timeoutTokenSource?.Dispose();
}
return _result;
}
/// <summary>
/// 核心执行逻辑(由子类实现)
/// </summary>
/// <param name="cancellationToken">取消令牌</param>
/// <returns></returns>
protected abstract Task ExecuteCoreAsync(CancellationToken cancellationToken);
/// <summary>
/// 更新执行进度
/// </summary>
/// <param name="progress">进度(0-100)</param>
protected void UpdateProgress(int progress)
{
_progressUpdateAction?.Invoke(_params.SegmentId, progress, SegmentStatus.Running);
}
}
/// <summary>
/// 数据查询业务段执行器
/// </summary>
public class DataQuerySegmentExecutor : BaseSegmentExecutor
{
private readonly IDbConnection _dbConnection;
public DataQuerySegmentExecutor(DataQuerySegmentParams segmentParams,
IDbConnection dbConnection,
CancellationToken cancellationToken,
Action<string, int, SegmentStatus> progressUpdateAction = null)
: base(segmentParams, cancellationToken, progressUpdateAction)
{
_dbConnection = dbConnection;
}
protected override async Task ExecuteCoreAsync(CancellationToken cancellationToken)
{
var queryParams = (DataQuerySegmentParams)_params;
UpdateProgress(20);
// 打开数据库连接
if (_dbConnection.State != ConnectionState.Open)
{
await _dbConnection.OpenAsync(cancellationToken);
}
UpdateProgress(40);
// 执行查询
var result = await _dbConnection.QueryAsync<dynamic>(
queryParams.Sql,
queryParams.QueryParams,
cancellationToken: cancellationToken);
UpdateProgress(80);
// 处理结果
if (queryParams.ReturnData)
{
_result.ResultData = JsonConvert.SerializeObject(result);
}
UpdateProgress(100);
}
}
/// <summary>
/// API调用业务段执行器
/// </summary>
public class ApiCallSegmentExecutor : BaseSegmentExecutor
{
private readonly HttpClient _httpClient;
public ApiCallSegmentExecutor(ApiCallSegmentParams segmentParams,
HttpClient httpClient,
CancellationToken cancellationToken,
Action<string, int, SegmentStatus> progressUpdateAction = null)
: base(segmentParams, cancellationToken, progressUpdateAction)
{
_httpClient = httpClient;
}
protected override async Task ExecuteCoreAsync(CancellationToken cancellationToken)
{
var apiParams = (ApiCallSegmentParams)_params;
UpdateProgress(10);
// 创建请求消息
var request = new HttpRequestMessage(new HttpMethod(apiParams.HttpMethod), apiParams.ApiUrl);
// 添加请求头
foreach (var header in apiParams.Headers)
{
request.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
UpdateProgress(30);
// 添加请求体
if (!string.IsNullOrEmpty(apiParams.RequestBody) &&
(apiParams.HttpMethod == "POST" || apiParams.HttpMethod == "PUT"))
{
request.Content = new StringContent(apiParams.RequestBody, Encoding.UTF8, "application/json");
}
UpdateProgress(50);
// 发送请求
var response = await _httpClient.SendAsync(request, cancellationToken);
UpdateProgress(70);
// 处理响应
response.EnsureSuccessStatusCode();
_result.ResultData = await response.Content.ReadAsStringAsync(cancellationToken);
UpdateProgress(100);
}
}
/// <summary>
/// 业务段执行器工厂
/// </summary>
public class SegmentExecutorFactory
{
private readonly IDbConnection _dbConnection;
private readonly HttpClient _httpClient;
public SegmentExecutorFactory(IDbConnection dbConnection, HttpClient httpClient)
{
_dbConnection = dbConnection;
_httpClient = httpClient;
}
/// <summary>
/// 创建业务段执行器
/// </summary>
/// <param name="segmentParams">业务段参数</param>
/// <param name="cancellationToken">取消令牌</param>
/// <param name="progressUpdateAction">进度更新委托</param>
/// <returns></returns>
/// <exception cref="NotSupportedException"></exception>
public BaseSegmentExecutor CreateExecutor(SegmentParams segmentParams,
CancellationToken cancellationToken,
Action<string, int, SegmentStatus> progressUpdateAction = null)
{
return segmentParams switch
{
DataQuerySegmentParams queryParams => new DataQuerySegmentExecutor(
queryParams, _dbConnection, cancellationToken, progressUpdateAction),
ApiCallSegmentParams apiParams => new ApiCallSegmentExecutor(
apiParams, _httpClient, cancellationToken, progressUpdateAction),
// 可扩展其他类型的业务段执行器
_ => throw new NotSupportedException($"不支持的业务段类型:{segmentParams.SegmentType}")
};
}
}
#endregion
2. 多结构并发调度引擎
csharp
运行
#region 多结构并发调度器
/// <summary>
/// 多结构业务段并发调度器
/// 功能:管理多结构下的业务段并发执行,处理资源隔离和并发控制
/// </summary>
public class MultiStructureConcurrentScheduler : IDisposable
{
// 单例实例
private static readonly Lazy<MultiStructureConcurrentScheduler> _instance =
new Lazy<MultiStructureConcurrentScheduler>(() => new MultiStructureConcurrentScheduler());
public static MultiStructureConcurrentScheduler Instance => _instance.Value;
// 业务段执行器工厂
private readonly SegmentExecutorFactory _executorFactory;
// 结构类型并发控制信号量(线程安全)
private readonly ConcurrentDictionary<string, SemaphoreSlim> _structureSemaphores =
new ConcurrentDictionary<string, SemaphoreSlim>();
// 业务段执行状态(线程安全)
private readonly ConcurrentDictionary<string, SegmentExecutionResult> _executionResults =
new ConcurrentDictionary<string, SegmentExecutionResult>();
// 取消令牌源(按批次ID)
private readonly ConcurrentDictionary<string, CancellationTokenSource> _batchCtsDict =
new ConcurrentDictionary<string, CancellationTokenSource>();
// 进度更新事件
public event Action<string, int, SegmentStatus> ProgressUpdated;
// 批次完成事件
public event Action<string, Dictionary<string, SegmentExecutionResult>> BatchCompleted;
/// <summary>
/// 私有构造函数
/// </summary>
private MultiStructureConcurrentScheduler()
{
// 初始化数据库连接和HttpClient
var dbConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["MESDB"].ConnectionString);
var httpClient = new HttpClient();
_executorFactory = new SegmentExecutorFactory(dbConnection, httpClient);
// 初始化默认结构类型的并发控制
var defaultStructures = new[] { "Line", "WorkOrder", "Process", "Station" };
foreach (var structure in defaultStructures)
{
_structureSemaphores.TryAdd(structure, new SemaphoreSlim(5, 20)); // 默认最大并发5
}
}
/// <summary>
/// 设置结构类型的最大并发数
/// </summary>
/// <param name="structureType">结构类型</param>
/// <param name="maxConcurrent">最大并发数</param>
public void SetStructureMaxConcurrent(string structureType, int maxConcurrent)
{
_structureSemaphores.AddOrUpdate(structureType,
_ => new SemaphoreSlim(maxConcurrent, maxConcurrent),
(_, old) => new SemaphoreSlim(maxConcurrent, maxConcurrent));
}
/// <summary>
/// 执行单个业务段
/// </summary>
/// <param name="segmentParams">业务段参数</param>
/// <returns></returns>
public async Task<SegmentExecutionResult> ExecuteSegmentAsync(SegmentParams segmentParams)
{
// 获取结构类型的并发信号量
var semaphore = _structureSemaphores.GetOrAdd(segmentParams.StructureType,
_ => new SemaphoreSlim(5, 20));
// 创建取消令牌
var cts = new CancellationTokenSource();
try
{
// 等待信号量
await semaphore.WaitAsync(cts.Token);
// 创建执行器
var executor = _executorFactory.CreateExecutor(
segmentParams,
cts.Token,
(id, progress, status) => OnProgressUpdated(id, progress, status));
// 执行业务段
var result = await executor.ExecuteAsync();
// 保存执行结果
_executionResults[segmentParams.SegmentId] = result;
return result;
}
finally
{
// 释放信号量
semaphore.Release();
cts.Dispose();
}
}
/// <summary>
/// 批量执行业务段(多结构并发)
/// </summary>
/// <param name="batchId">批次ID</param>
/// <param name="segmentParamsList">业务段参数列表</param>
/// <param name="concurrentStrategy">并发策略</param>
/// <returns></returns>
public async Task ExecuteBatchSegmentsAsync(string batchId,
List<SegmentParams> segmentParamsList,
ConcurrentStrategy concurrentStrategy = ConcurrentStrategy.Parallel)
{
// 创建批次取消令牌
var batchCts = new CancellationTokenSource();
_batchCtsDict[batchId] = batchCts;
var batchResults = new Dictionary<string, SegmentExecutionResult>();
var segmentTasks = new List<Task>();
try
{
// 根据并发策略执行
switch (concurrentStrategy)
{
case ConcurrentStrategy.Parallel:
// 纯并行执行所有业务段
foreach (var segmentParams in segmentParamsList)
{
segmentTasks.Add(ExecuteSegmentInternalAsync(segmentParams, batchCts.Token, batchResults));
}
break;
case ConcurrentStrategy.Sequential:
// 串行执行(按优先级)
var sortedSegments = segmentParamsList.OrderBy(s => s.Priority).ToList();
foreach (var segmentParams in sortedSegments)
{
await ExecuteSegmentInternalAsync(segmentParams, batchCts.Token, batchResults);
}
break;
case ConcurrentStrategy.Batch:
// 按批次并行执行(每批5个)
var batches = segmentParamsList.Chunk(5);
foreach (var batch in batches)
{
var batchTasks = batch.Select(s => ExecuteSegmentInternalAsync(s, batchCts.Token, batchResults)).ToList();
await Task.WhenAll(batchTasks);
}
break;
case ConcurrentStrategy.Priority:
// 按优先级分组并行
var priorityGroups = segmentParamsList.GroupBy(s => s.Priority).OrderBy(g => g.Key);
foreach (var group in priorityGroups)
{
var groupTasks = group.Select(s => ExecuteSegmentInternalAsync(s, batchCts.Token, batchResults)).ToList();
await Task.WhenAll(groupTasks);
}
break;
}
// 等待所有任务完成
if (segmentTasks.Any())
{
await Task.WhenAll(segmentTasks);
}
}
catch (Exception ex)
{
Console.WriteLine($"批次执行异常:{ex.Message}");
}
finally
{
// 触发批次完成事件
BatchCompleted?.Invoke(batchId, batchResults);
// 清理取消令牌
_batchCtsDict.TryRemove(batchId, out _);
batchCts.Dispose();
}
}
/// <summary>
/// 内部执行单个业务段的方法
/// </summary>
private async Task ExecuteSegmentInternalAsync(SegmentParams segmentParams,
CancellationToken cancellationToken,
Dictionary<string, SegmentExecutionResult> batchResults)
{
var result = await ExecuteSegmentAsync(segmentParams);
batchResults[segmentParams.SegmentId] = result;
}
/// <summary>
/// 取消批次执行
/// </summary>
/// <param name="batchId">批次ID</param>
public void CancelBatchExecution(string batchId)
{
if (_batchCtsDict.TryGetValue(batchId, out var cts))
{
cts.Cancel();
Console.WriteLine($"批次{batchId}执行已取消");
}
}
/// <summary>
/// 获取业务段执行结果
/// </summary>
/// <param name="segmentId">业务段ID</param>
/// <returns></returns>
public SegmentExecutionResult GetSegmentResult(string segmentId)
{
_executionResults.TryGetValue(segmentId, out var result);
return result;
}
/// <summary>
/// 清理执行结果
/// </summary>
/// <param name="keepHours">保留小时数</param>
public void CleanupExecutionResults(int keepHours = 24)
{
var cutoffTime = DateTime.Now.AddHours(-keepHours);
var keysToRemove = _executionResults.Where(kv =>
kv.Value.EndTime < cutoffTime).Select(kv => kv.Key).ToList();
foreach (var key in keysToRemove)
{
_executionResults.TryRemove(key, out _);
}
}
/// <summary>
/// 进度更新事件触发
/// </summary>
private void OnProgressUpdated(string segmentId, int progress, SegmentStatus status)
{
ProgressUpdated?.Invoke(segmentId, progress, status);
}
/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
// 释放所有信号量
foreach (var semaphore in _structureSemaphores.Values)
{
semaphore.Dispose();
}
// 取消所有批次
foreach (var cts in _batchCtsDict.Values)
{
cts.Cancel();
cts.Dispose();
}
_structureSemaphores.Clear();
_batchCtsDict.Clear();
_executionResults.Clear();
}
}
#endregion
3. 可视化界面组件(WinForm)
csharp
运行
#region WinForm可视化界面
public partial class BusinessSegmentExecutorForm : Form
{
// 并发调度器
private readonly MultiStructureConcurrentScheduler _scheduler =
MultiStructureConcurrentScheduler.Instance;
// 批次ID
private string _currentBatchId = Guid.NewGuid().ToString("N");
public BusinessSegmentExecutorForm()
{
InitializeComponent();
// 注册事件
_scheduler.ProgressUpdated += OnProgressUpdated;
_scheduler.BatchCompleted += OnBatchCompleted;
// 初始化UI
InitUI();
}
/// <summary>
/// 初始化UI
/// </summary>
private void InitUI()
{
// 结构类型下拉框
cboStructureType.Items.AddRange(new[] { "Line", "WorkOrder", "Process", "Station" });
cboStructureType.SelectedIndex = 0;
// 业务段类型下拉框
cboSegmentType.Items.AddRange(Enum.GetNames(typeof(BusinessSegmentType)));
cboSegmentType.SelectedIndex = 0;
// 并发策略下拉框
cboConcurrentStrategy.Items.AddRange(Enum.GetNames(typeof(ConcurrentStrategy)));
cboConcurrentStrategy.SelectedIndex = 0;
// 初始化业务段列表DataGridView
dgvSegments.Columns.AddRange(new DataGridViewColumn[]
{
new DataGridViewTextBoxColumn { Name = "SegmentId", HeaderText = "业务段ID", Width = 150 },
new DataGridViewTextBoxColumn { Name = "SegmentName", HeaderText = "业务段名称", Width = 150 },
new DataGridViewTextBoxColumn { Name = "SegmentType", HeaderText = "类型", Width = 100 },
new DataGridViewTextBoxColumn { Name = "StructureType", HeaderText = "结构类型", Width = 100 },
new DataGridViewTextBoxColumn { Name = "StructureId", HeaderText = "结构ID", Width = 100 },
new DataGridViewTextBoxColumn { Name = "Status", HeaderText = "状态", Width = 100 },
new DataGridViewTextBoxColumn { Name = "Progress", HeaderText = "进度", Width = 80 },
new DataGridViewTextBoxColumn { Name = "ExecutionTime", HeaderText = "执行耗时(ms)", Width = 120 },
new DataGridViewTextBoxColumn { Name = "ErrorMessage", HeaderText = "错误信息", Width = 200 }
});
// 按钮事件
btnAddSegment.Click += BtnAddSegment_Click;
btnExecuteBatch.Click += BtnExecuteBatch_Click;
btnCancelBatch.Click += BtnCancelBatch_Click;
btnClearSegments.Click += BtnClearSegments_Click;
btnSetMaxConcurrent.Click += BtnSetMaxConcurrent_Click;
}
/// <summary>
/// 添加业务段
/// </summary>
private void BtnAddSegment_Click(object sender, EventArgs e)
{
try
{
SegmentParams segmentParams = null;
var segmentType = (BusinessSegmentType)Enum.Parse(typeof(BusinessSegmentType), cboSegmentType.SelectedItem.ToString());
// 根据业务段类型创建参数对象
switch (segmentType)
{
case BusinessSegmentType.DataQuery:
segmentParams = new DataQuerySegmentParams
{
SegmentName = txtSegmentName.Text,
StructureType = cboStructureType.SelectedItem.ToString(),
StructureId = txtStructureId.Text,
Priority = (int)nudPriority.Value,
Timeout = (int)nudTimeout.Value,
RetryCount = (int)nudRetryCount.Value,
AllowSkip = chkAllowSkip.Checked,
Sql = txtSql.Text,
QueryParams = new Dictionary<string, object>
{
{ "WorkOrderId", txtWorkOrderId.Text }
}
};
break;
case BusinessSegmentType.ApiCall:
segmentParams = new ApiCallSegmentParams
{
SegmentName = txtSegmentName.Text,
StructureType = cboStructureType.SelectedItem.ToString(),
StructureId = txtStructureId.Text,
Priority = (int)nudPriority.Value,
Timeout = (int)nudTimeout.Value,
RetryCount = (int)nudRetryCount.Value,
AllowSkip = chkAllowSkip.Checked,
ApiUrl = txtApiUrl.Text,
HttpMethod = cboHttpMethod.SelectedItem.ToString(),
RequestBody = txtRequestBody.Text
};
break;
default:
MessageBox.Show("暂不支持该业务段类型", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
// 添加到列表
var row = dgvSegments.Rows.Add();
row.Cells["SegmentId"].Value = segmentParams.SegmentId;
row.Cells["SegmentName"].Value = segmentParams.SegmentName;
row.Cells["SegmentType"].Value = segmentParams.SegmentType.ToString();
row.Cells["StructureType"].Value = segmentParams.StructureType;
row.Cells["StructureId"].Value = segmentParams.StructureId;
row.Cells["Status"].Value = SegmentStatus.Pending.ToString();
row.Cells["Progress"].Value = "0%";
row.Cells["ExecutionTime"].Value = "";
row.Cells["ErrorMessage"].Value = "";
// 保存参数到行的Tag属性
row.Tag = segmentParams;
MessageBox.Show("业务段添加成功", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"添加业务段失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 执行批次
/// </summary>
private async void BtnExecuteBatch_Click(object sender, EventArgs e)
{
if (dgvSegments.Rows.Count == 0)
{
MessageBox.Show("请先添加业务段", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
try
{
// 获取所有业务段参数
var segmentParamsList = new List<SegmentParams>();
foreach (DataGridViewRow row in dgvSegments.Rows)
{
if (row.Tag is SegmentParams param)
{
segmentParamsList.Add(param);
}
}
// 获取并发策略
var concurrentStrategy = (ConcurrentStrategy)Enum.Parse(
typeof(ConcurrentStrategy), cboConcurrentStrategy.SelectedItem.ToString());
// 生成新的批次ID
_currentBatchId = Guid.NewGuid().ToString("N");
// 异步执行批次
await Task.Run(async () =>
{
await _scheduler.ExecuteBatchSegmentsAsync(
_currentBatchId, segmentParamsList, concurrentStrategy);
});
MessageBox.Show("批次执行完成", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"执行批次失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 取消批次
/// </summary>
private void BtnCancelBatch_Click(object sender, EventArgs e)
{
try
{
_scheduler.CancelBatchExecution(_currentBatchId);
MessageBox.Show("批次取消请求已提交", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"取消批次失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 进度更新
/// </summary>
private void OnProgressUpdated(string segmentId, int progress, SegmentStatus status)
{
if (dgvSegments.InvokeRequired)
{
dgvSegments.Invoke(new Action(() => UpdateSegmentProgress(segmentId, progress, status)));
}
else
{
UpdateSegmentProgress(segmentId, progress, status);
}
}
/// <summary>
/// 更新业务段进度
/// </summary>
private void UpdateSegmentProgress(string segmentId, int progress, SegmentStatus status)
{
foreach (DataGridViewRow row in dgvSegments.Rows)
{
if (row.Cells["SegmentId"].Value?.ToString() == segmentId)
{
row.Cells["Status"].Value = status.ToString();
row.Cells["Progress"].Value = $"{progress}%";
// 根据状态设置行颜色
row.DefaultCellStyle.BackColor = status switch
{
SegmentStatus.Running => Color.LightYellow,
SegmentStatus.Completed => Color.LightGreen,
SegmentStatus.Failed => Color.LightPink,
SegmentStatus.Skipped => Color.LightBlue,
SegmentStatus.Cancelled => Color.LightGray,
_ => Color.White
};
// 如果执行完成,更新执行耗时
if (status == SegmentStatus.Completed || status == SegmentStatus.Failed || status == SegmentStatus.Skipped)
{
var result = _scheduler.GetSegmentResult(segmentId);
if (result != null)
{
row.Cells["ExecutionTime"].Value = result.ExecutionTimeMs;
row.Cells["ErrorMessage"].Value = result.ErrorMessage;
}
}
break;
}
}
}
/// <summary>
/// 批次完成事件处理
/// </summary>
private void OnBatchCompleted(string batchId, Dictionary<string, SegmentExecutionResult> results)
{
if (InvokeRequired)
{
Invoke(new Action(() =>
{
MessageBox.Show($"批次{batchId}执行完成,总计{results.Count}个业务段",
"批次完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
}));
}
else
{
MessageBox.Show($"批次{batchId}执行完成,总计{results.Count}个业务段",
"批次完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
/// <summary>
/// 设置最大并发数
/// </summary>
private void BtnSetMaxConcurrent_Click(object sender, EventArgs e)
{
try
{
var structureType = cboStructureType.SelectedItem.ToString();
var maxConcurrent = (int)nudMaxConcurrent.Value;
_scheduler.SetStructureMaxConcurrent(structureType, maxConcurrent);
MessageBox.Show($"结构类型{structureType}的最大并发数已设置为{maxConcurrent}",
"成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"设置最大并发数失败:{ex.Message}",
"错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 清空业务段列表
/// </summary>
private void BtnClearSegments_Click(object sender, EventArgs e)
{
dgvSegments.Rows.Clear();
}
/// <summary>
/// 窗体关闭时清理资源
/// </summary>
private void BusinessSegmentExecutorForm_FormClosing(object sender, FormClosingEventArgs e)
{
_scheduler.ProgressUpdated -= OnProgressUpdated;
_scheduler.BatchCompleted -= OnBatchCompleted;
_scheduler.Dispose();
}
}
#endregion
4. API 接口组件
csharp
运行
#region API接口控制器
[Route("api/[controller]")]
[ApiController]
public class BusinessSegmentController : ControllerBase
{
private readonly MultiStructureConcurrentScheduler _scheduler =
MultiStructureConcurrentScheduler.Instance;
private readonly ILogger<BusinessSegmentController> _logger;
public BusinessSegmentController(ILogger<BusinessSegmentController> logger)
{
_logger = logger;
}
/// <summary>
/// 执行单个业务段
/// </summary>
/// <param name="segmentRequest">业务段请求</param>
/// <returns></returns>
[HttpPost("execute")]
public async Task<IActionResult> ExecuteSegment([FromBody] SegmentRequest segmentRequest)
{
try
{
// 转换为业务段参数
SegmentParams segmentParams = ConvertToSegmentParams(segmentRequest);
if (segmentParams == null)
{
return BadRequest("不支持的业务段类型");
}
// 执行业务段
var result = await _scheduler.ExecuteSegmentAsync(segmentParams);
_logger.LogInformation($"业务段{segmentParams.SegmentId}执行完成,状态:{result.Status}");
return Ok(new
{
Success = true,
Data = result
});
}
catch (Exception ex)
{
_logger.LogError(ex, "执行业务段失败");
return StatusCode(500, new
{
Success = false,
Message = ex.Message
});
}
}
/// <summary>
/// 批量执行业务段
/// </summary>
/// <param name="batchRequest">批次请求</param>
/// <returns></returns>
[HttpPost("execute-batch")]
public async Task<IActionResult> ExecuteBatch([FromBody] BatchRequest batchRequest)
{
try
{
// 转换业务段参数列表
var segmentParamsList = batchRequest.Segments
.Select(ConvertToSegmentParams)
.Where(p => p != null)
.ToList();
if (!segmentParamsList.Any())
{
return BadRequest("无效的业务段参数");
}
// 生成批次ID
var batchId = batchRequest.BatchId ?? Guid.NewGuid().ToString("N");
// 异步执行批次(不等待完成)
_ = Task.Run(async () =>
{
await _scheduler.ExecuteBatchSegmentsAsync(
batchId,
segmentParamsList,
batchRequest.ConcurrentStrategy);
});
_logger.LogInformation($"批次{batchId}已提交执行,包含{segmentParamsList.Count}个业务段");
return Ok(new
{
Success = true,
BatchId = batchId,
Message = "批次已提交执行"
});
}
catch (Exception ex)
{
_logger.LogError(ex, "提交批次执行失败");
return StatusCode(500, new
{
Success = false,
Message = ex.Message
});
}
}
/// <summary>
/// 取消批次执行
/// </summary>
/// <param name="batchId">批次ID</param>
/// <returns></returns>
[HttpPost("cancel-batch/{batchId}")]
public IActionResult CancelBatch(string batchId)
{
try
{
_scheduler.CancelBatchExecution(batchId);
_logger.LogInformation($"批次{batchId}取消请求已提交");
return Ok(new
{
Success = true,
Message = "批次取消请求已提交"
});
}
catch (Exception ex)
{
_logger.LogError(ex, $"取消批次{batchId}失败");
return StatusCode(500, new
{
Success = false,
Message = ex.Message
});
}
}
/// <summary>
/// 获取业务段执行结果
/// </summary>
/// <param name="segmentId">业务段ID</param>
/// <returns></returns>
[HttpGet("result/{segmentId}")]
public IActionResult GetSegmentResult(string segmentId)
{
try
{
var result = _scheduler.GetSegmentResult(segmentId);
if (result == null)
{
return NotFound(new
{
Success = false,
Message = "业务段执行结果不存在"
});
}
return Ok(new
{
Success = true,
Data = result
});
}
catch (Exception ex)
{
_logger.LogError(ex, $"获取业务段{segmentId}执行结果失败");
return StatusCode(500, new
{
Success = false,
Message = ex.Message
});
}
}
/// <summary>
/// 设置结构类型最大并发数
/// </summary>
/// <param name="structureType">结构类型</param>
/// <param name="maxConcurrent">最大并发数</param>
/// <returns></returns>
[HttpPost("set-max-concurrent/{structureType}/{maxConcurrent}")]
public IActionResult SetMaxConcurrent(string structureType, int maxConcurrent)
{
try
{
_scheduler.SetStructureMaxConcurrent(structureType, maxConcurrent);
_logger.LogInformation($"结构类型{structureType}最大并发数已设置为{maxConcurrent}");
return Ok(new
{
Success = true,
Message = $"结构类型{structureType}最大并发数已设置为{maxConcurrent}"
});
}
catch (Exception ex)
{
_logger.LogError(ex, $"设置结构类型{structureType}最大并发数失败");
return StatusCode(500, new
{
Success = false,
Message = ex.Message
});
}
}
/// <summary>
/// 转换请求模型到业务段参数
/// </summary>
private SegmentParams ConvertToSegmentParams(SegmentRequest request)
{
return request.SegmentType switch
{
"DataQuery" => new DataQuerySegmentParams
{
SegmentName = request.SegmentName,
StructureType = request.StructureType,
StructureId = request.StructureId,
Priority = request.Priority ?? 5,
Timeout = request.Timeout ?? 30,
RetryCount = request.RetryCount ?? 0,
AllowSkip = request.AllowSkip ?? false,
Sql = request.BusinessParams?["Sql"]?.ToString(),
QueryParams = JsonConvert.DeserializeObject<Dictionary<string, object>>(
request.BusinessParams?["QueryParams"]?.ToString() ?? "{}")
},
"ApiCall" => new ApiCallSegmentParams
{
SegmentName = request.SegmentName,
StructureType = request.StructureType,
StructureId = request.StructureId,
Priority = request.Priority ?? 5,
Timeout = request.Timeout ?? 30,
RetryCount = request.RetryCount ?? 0,
AllowSkip = request.AllowSkip ?? false,
ApiUrl = request.BusinessParams?["ApiUrl"]?.ToString(),
HttpMethod = request.BusinessParams?["HttpMethod"]?.ToString() ?? "POST",
RequestBody = request.BusinessParams?["RequestBody"]?.ToString() ?? "{}",
Headers = JsonConvert.DeserializeObject<Dictionary<string, string>>(
request.BusinessParams?["Headers"]?.ToString() ?? "{}")
},
_ => null
};
}
}
/// <summary>
/// 业务段请求模型
/// </summary>
public class SegmentRequest
{
public string SegmentName { get; set; }
public string SegmentType { get; set; }
public string StructureType { get; set; }
public string StructureId { get; set; }
public int? Priority { get; set; }
public int? Timeout { get; set; }
public int? RetryCount { get; set; }
public bool? AllowSkip { get; set; }
public Dictionary<string, object> BusinessParams { get; set; } = new Dictionary<string, object>();
}
/// <summary>
/// 批次请求模型
/// </summary>
public class BatchRequest
{
public string BatchId { get; set; }
public List<SegmentRequest> Segments { get; set; } = new List<SegmentRequest>();
public ConcurrentStrategy ConcurrentStrategy { get; set; } = ConcurrentStrategy.Parallel;
}
#endregion
三、使用示例
1. 基础使用流程
csharp
运行
// 1. 初始化调度器
var scheduler = MultiStructureConcurrentScheduler.Instance;
// 2. 设置产线结构的最大并发数
scheduler.SetStructureMaxConcurrent("Line", 10);
// 3. 创建业务段参数
var queryParams = new DataQuerySegmentParams
{
SegmentName = "查询工单信息",
StructureType = "Line",
StructureId = "LINE001",
Priority = 1,
Timeout = 10,
RetryCount = 2,
Sql = "SELECT * FROM WorkOrder WHERE LineCode = @LineCode",
QueryParams = new Dictionary<string, object> { { "LineCode", "LINE001" } }
};
var apiParams = new ApiCallSegmentParams
{
SegmentName = "推送工单数据到ERP",
StructureType = "Line",
StructureId = "LINE001",
Priority = 2,
Timeout = 20,
RetryCount = 3,
ApiUrl = "http://erp-system/api/workorder/sync",
HttpMethod = "POST",
RequestBody = JsonConvert.SerializeObject(new { LineCode = "LINE001" })
};
// 4. 批量执行
var batchId = Guid.NewGuid().ToString("N");
await scheduler.ExecuteBatchSegmentsAsync(
batchId,
new List<SegmentParams> { queryParams, apiParams },
ConcurrentStrategy.Parallel);
// 5. 获取执行结果
var queryResult = scheduler.GetSegmentResult(queryParams.SegmentId);
var apiResult = scheduler.GetSegmentResult(apiParams.SegmentId);
Console.WriteLine($"查询业务段状态:{queryResult.Status},耗时:{queryResult.ExecutionTimeMs}ms");
Console.WriteLine($"API调用业务段状态:{apiResult.Status},耗时:{apiResult.ExecutionTimeMs}ms");
2. 典型 MES/ERP 应用场景
csharp
运行
// 场景:工单完工处理(包含多个独立业务段)
public async Task ProcessWorkOrderCompletion(string workOrderId)
{
var scheduler = MultiStructureConcurrentScheduler.Instance;
var batchId = $"WO_{workOrderId}_{DateTime.Now:yyyyMMddHHmmss}";
// 业务段1:查询工单基本信息
var queryWorkOrderParams = new DataQuerySegmentParams
{
SegmentName = "查询工单基本信息",
StructureType = "WorkOrder",
StructureId = workOrderId,
Priority = 1,
Sql = "SELECT * FROM WorkOrder WHERE WorkOrderId = @WorkOrderId",
QueryParams = new Dictionary<string, object> { { "WorkOrderId", workOrderId } }
};
// 业务段2:查询工单生产数据
var queryProductionParams = new DataQuerySegmentParams
{
SegmentName = "查询工单生产数据",
StructureType = "WorkOrder",
StructureId = workOrderId,
Priority = 1,
Sql = "SELECT * FROM ProductionData WHERE WorkOrderId = @WorkOrderId",
QueryParams = new Dictionary<string, object> { { "WorkOrderId", workOrderId } }
};
// 业务段3:更新工单状态
var updateStatusParams = new DataQuerySegmentParams
{
SegmentName = "更新工单状态为已完工",
StructureType = "WorkOrder",
StructureId = workOrderId,
Priority = 2,
Sql = "UPDATE WorkOrder SET Status = 'Completed', CompleteTime = GETDATE() WHERE WorkOrderId = @WorkOrderId",
QueryParams = new Dictionary<string, object> { { "WorkOrderId", workOrderId } },
ReturnData = false
};
// 业务段4:推送完工数据到ERP
var pushToErpParams = new ApiCallSegmentParams
{
SegmentName = "推送工单完工数据到ERP",
StructureType = "WorkOrder",
StructureId = workOrderId,
Priority = 3,
ApiUrl = "http://erp-system/api/workorder/complete",
RequestBody = JsonConvert.SerializeObject(new { WorkOrderId = workOrderId })
};
// 业务段5:生成完工报告
var generateReportParams = new ApiCallSegmentParams
{
SegmentName = "生成工单完工报告",
StructureType = "WorkOrder",
StructureId = workOrderId,
Priority = 3,
ApiUrl = "http://report-system/api/report/generate",
RequestBody = JsonConvert.SerializeObject(new { WorkOrderId = workOrderId, ReportType = "Completion" })
};
// 批量并行执行(前两个并行,后三个按优先级)
var segmentList = new List<SegmentParams>
{
queryWorkOrderParams,
queryProductionParams,
updateStatusParams,
pushToErpParams,
generateReportParams
};
await scheduler.ExecuteBatchSegmentsAsync(batchId, segmentList, ConcurrentStrategy.Priority);
// 检查执行结果
var results = segmentList.ToDictionary(
s => s.SegmentName,
s => scheduler.GetSegmentResult(s.SegmentId).Status);
foreach (var kvp in results)
{
Console.WriteLine($"业务段「{kvp.Key}」执行状态:{kvp.Value}");
}
}
四、总结
关键点回顾
- 原子化业务封装:将 MES/ERP 中繁复琐碎的独立业务语句封装为标准化业务段,支持数据查询、API 调用等多种类型,通过参数化配置减少代码冗余;
- 多线程并发执行:基于 TPL 实现业务段的并行执行,支持纯并行、串行、批量、优先级等多种并发策略,显著提升多段独立业务的处理效率;
- 多结构并发控制:按产线 / 工单 / 工序等结构类型进行分级并发控制,通过信号量实现资源隔离,避免并发冲突;
- 高可靠性设计:内置超时控制、自动重试、失败跳过机制,保证单个业务段失败不影响整体执行;
- 全栈组件化方案:包含可视化 WinForm 界面、高性能后台调度引擎、标准化 REST API,支持本地操作和外部系统集成;
- 实时监控能力:提供进度更新、状态追踪、执行耗时统计,便于问题定位和性能优化。
该方案完美适配 MES/ERP 场景中多段独立不相关业务的并发处理需求,解决了传统串行执行效率低、代码冗余易出错的问题,同时保证了系统的稳定性和可维护性,可直接应用于工单处理、数据同步、报表生成等典型 MES/ERP 业务场景。