对 StartQuery 相关代码的进一步细化优化,重点聚焦于异步实现、定时器优化、特定硬件适配和性能调优。我将提供具体的异步版本代码,优化定时器机制,并考虑硬件适配的灵活性,同时结合性能调优策略。每个部分都会详细解释优化细节和实现逻辑,保持中文解释清晰易懂。
优化目标
异步实现:将同步的硬件查询逻辑改为异步,使用 async/await 提高 IO 密集型操作的性能。
定时器优化:替换 System.Timers.Timer 为更现代的 PeriodicTimer,支持异步操作并提供更灵活的控制。
硬件适配:设计灵活的接口,适配不同硬件 API(同步/异步),并支持可配置的查询参数。
性能调优:减少锁竞争、优化线程管理、降低 CPU 和内存开销。
错误处理和日志:增强异常处理和日志记录,便于调试和监控。
问题回顾
-
当前问题:
-
StartQuery 使用两个线程(_StartQuery 和 _StartQueryAdapterBoard),但共享 HardwareMgr.DAQLocks[SectionId] 和静态 m_Locker,导致锁竞争和潜在死锁风险。
-
Thread.Sleep(15) 忙等待导致 CPU 占用高。
-
同步调用 m_Hardware.QueryData 可能阻塞线程,限制性能。
-
异常处理不统一,_StartQueryAdapterBoard 的空 catch 块可能隐藏错误。
-
-
需求:
-
异步实现以支持现代硬件 API。
-
优化定时器机制以降低资源占用。
-
适配不同硬件 API(同步/异步)。
-
性能调优以提高吞吐量和响应性。
-
优化方案
1. 异步实现
-
方案:将 m_Hardware.QueryData 和 m_Hardware.ReadData 改为异步方法,使用 SemaphoreSlim 替代 lock 支持异步锁。
-
技术:使用 async/await 和 Task,确保非阻塞调用。
-
好处:减少线程阻塞,提高 IO 密集型操作的性能。
2. 定时器优化
-
方案:使用 .NET 6+ 的 PeriodicTimer 替代 System.Timers.Timer,支持异步定时操作,配合 CancellationToken 提供优雅的停止机制。
-
好处:更现代的 API,降低资源占用,支持异步操作,易于取消。
3. 硬件适配
-
方案:定义硬件访问接口(如 IHardware),支持同步和异步实现,允许动态配置查询指令和参数。
-
好处:提高代码灵活性,适配不同硬件 API,方便扩展。
4. 性能调优
-
方案:
-
合并 _StartQuery 和 _StartQueryAdapterBoard 为单一异步任务,减少线程开销。
-
使用批量查询(如果硬件支持)减少硬件访问次数。
-
优化状态管理,使用 volatile 或 Interlocked 确保线程安全。
-
-
好处:降低上下文切换开销,减少锁竞争,提高吞吐量。
5. 错误处理和日志
-
方案:统一异常处理,添加详细日志,记录硬件状态和错误信息。
-
好处:提高调试效率,增强系统健壮性。
优化后的代码
以下是完整的异步实现代码,包含定时器优化、硬件适配和性能调优。
1. 硬件接口定义
定义 IHardware 接口,支持同步和异步硬件访问。
csharp
public interface IHardware
{
bool Connected { get; }
Task<HardwareResult> QueryDataAsync(string instruction, CancellationToken cancellationToken = default);
Task<HardwareResult> ReadDataAsync(CancellationToken cancellationToken = default);
}
public class Hardware : IHardware
{
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
public bool Connected { get; set; } // 硬件连接状态
public async Task<HardwareResult> QueryDataAsync(string instruction, CancellationToken cancellationToken = default)
{
await _semaphore.WaitAsync(cancellationToken);
try
{
// 模拟异步硬件查询
await Task.Delay(10, cancellationToken); // 替换为实际硬件 API
return new HardwareResult(); // 示例实现
}
finally
{
_semaphore.Release();
}
}
public async Task<HardwareResult> ReadDataAsync(CancellationToken cancellationToken = default)
{
await _semaphore.WaitAsync(cancellationToken);
try
{
// 模拟异步读取
await Task.Delay(10, cancellationToken); // 替换为实际硬件 API
return new HardwareResult(); // 示例实现
}
finally
{
_semaphore.Release();
}
}
}
解释:
-
接口设计:IHardware 定义异步方法,支持不同硬件实现。
-
异步锁:使用 SemaphoreSlim 替代 lock,支持异步操作。
-
取消支持:添加 CancellationToken 参数,允许中断硬件查询。
2. 优化 StartQuery 和采集逻辑
使用 PeriodicTimer 和异步方法,合并线程,统一采集逻辑。
csharp
private PeriodicTimer _queryTimer;
private CancellationTokenSource _cts = new CancellationTokenSource();
private volatile bool _isRunning = false;
private volatile bool _firstRate = true;
private volatile string _lastErrorCode = string.Empty;
public async Task StartQueryAsync()
{
if (_isRunning)
return; // 防止重复启动
_isRunning = true;
RunningStatus = RunningStatus.Running;
// 初始化硬件
if (!await InitializeHardwareAsync(_cts.Token))
{
await StopQueryAsync();
return;
}
SystemNotifEvent.HardInfoNotifEvent(this, $"{Name}: 开始状态巡检", false);
// 初始化 PeriodicTimer,100ms 间隔(可配置)
_queryTimer = new PeriodicTimer(TimeSpan.FromMilliseconds(100));
try
{
while (await _queryTimer.WaitForNextTickAsync(_cts.Token))
{
if (!_isRunning || !m_Hardware.Connected)
{
await StopQueryAsync();
break;
}
try
{
await RateQueryAsync();
await QueryAdapterBoardAsync();
JudgMentBIBStatus();
}
catch (Exception ex)
{
HandleException(ex, "巡检状态异常");
}
}
}
catch (OperationCanceledException)
{
// 正常取消
await StopQueryAsync();
}
catch (Exception ex)
{
HandleException(ex, "巡检循环异常");
await StopQueryAsync();
}
}
public async Task StopQueryAsync()
{
if (!_isRunning)
return;
_isRunning = false;
_cts.Cancel();
_queryTimer?.Dispose();
_queryTimer = null;
StoppedQuery = true;
m_RateQuery = false;
SystemNotifEvent.HardInfoNotifEvent(this, $"{Name}: 已退出状态巡检", false);
_cts.Dispose();
_cts = new CancellationTokenSource();
}
private async Task<bool> InitializeHardwareAsync(CancellationToken cancellationToken)
{
try
{
if (m_Hardware == null)
{
await InitializeAsync(cancellationToken); // 假设 Initialize 支持异步
if (m_Hardware == null)
{
HandleException(new Exception("硬件未找到"), "未找到硬件");
return false;
}
}
if (!m_Hardware.Connected)
{
HandleException(new Exception("硬件未连接"), "硬件未连接");
return false;
}
return true;
}
catch (Exception ex)
{
HandleException(ex, "硬件初始化失败");
return false;
}
}
private async Task RateQueryAsync()
{
try
{
if (m_TestStaus)
return;
HardwareResult hardwareResult = ReadLooping
? await m_Hardware.ReadDataAsync(_cts.Token)
: await m_Hardware.QueryDataAsync("DAQREAD ", _cts.Token);
bool changed = _lastErrorCode != hardwareResult.Error.ToString();
_lastErrorCode = hardwareResult.Error.ToString();
if (hardwareResult.Error.ToString() == "0000")
{
if (changed && HardwareConnectStatus != HardwareConnectStatus.InUsing)
{
HardwareConnectStatus = HardwareConnectStatus.InUsing;
if (!_firstRate)
{
SystemNotifEvent.HardInfoNotifEvent(this, $"{Name} 采集板状态恢复正常。", true);
}
}
BIBStatus = Convert.ToInt32(hardwareResult.ResultMap["BIBOnOffLineStatus"]);
DAQStatus = Convert.ToInt32(hardwareResult.ResultMap["DAQStatus"]);
}
else if (changed)
{
ProcessError(hardwareResult, HardwareConnectStatus.InUsing);
}
}
catch (Exception ex)
{
bool changed = LastExceptionMsg != ex.Message;
if (changed)
{
LastExceptionMsg = ex.Message;
HandleException(ex, "采集板巡检状态异常");
}
}
finally
{
_firstRate = false;
}
}
private async Task QueryAdapterBoardAsync()
{
try
{
HardwareResult resultAdapterBoard = await m_Hardware.QueryDataAsync("DAQREADADAPTERBOARD ", _cts.Token);
if (resultAdapterBoard != null)
{
AdapterBoardTemp = Convert.ToDouble(resultAdapterBoard.ResultMap["AdapterBoardTemp"]);
}
}
catch (Exception ex)
{
HandleException(ex, "适配板数据读取异常");
}
}
private void HandleException(Exception ex, string message)
{
ExceptionDoEvnets(ex);
m_Log.Error($"{Name}: {message}: {ex.Message}");
SystemNotifEvent.HardErrorNotifEvent(this, $"{Name}: {message}", "");
}
解释:
-
异步实现:所有硬件访问方法(QueryDataAsync, ReadDataAsync)都使用 async/await,支持非阻塞操作。
-
PeriodicTimer:使用 .NET 6+ 的 PeriodicTimer,支持异步定时,配合 CancellationToken 提供优雅取消机制。
-
合并线程:将主板和适配板采集合并为单一异步任务,减少线程开销。
-
取消支持:通过 _cts 实现采集任务的取消,确保优雅停止。
-
硬件初始化:提取 InitializeHardwareAsync,支持异步初始化,减少代码重复。
-
线程安全:使用 volatile 标志位 _isRunning, _firstRate, _lastErrorCode,防止数据竞争。
3. 硬件适配配置
支持可配置的硬件查询参数,适配不同硬件。
csharp
public class HardwareConfig
{
public string QueryInstruction { get; set; } = "DAQREAD";
public string AdapterBoardQueryInstruction { get; set; } = "DAQREADADAPTERBOARD";
public int QueryIntervalMs { get; set; } = 100; // 默认 100ms
}
public class Hardware : IHardware
{
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
private readonly HardwareConfig _config;
public bool Connected { get; set; }
public Hardware(HardwareConfig config)
{
_config = config ?? throw new ArgumentNullException(nameof(config));
}
public async Task<HardwareResult> QueryDataAsync(string instruction, CancellationToken cancellationToken = default)
{
await _semaphore.WaitAsync(cancellationToken);
try
{
// 根据配置动态调整指令
string actualInstruction = instruction switch
{
"DAQREAD" => _config.QueryInstruction,
"DAQREADADAPTERBOARD" => _config.AdapterBoardQueryInstruction,
_ => instruction
};
// 模拟硬件查询
await Task.Delay(10, cancellationToken); // 替换为实际硬件 API
return new HardwareResult();
}
finally
{
_semaphore.Release();
}
}
public async Task<HardwareResult> ReadDataAsync(CancellationToken cancellationToken = default)
{
return await QueryDataAsync(_config.QueryInstruction, cancellationToken);
}
}
解释:
-
配置类:HardwareConfig 允许动态配置查询指令和间隔,适配不同硬件。
-
动态指令:QueryDataAsync 根据配置选择实际指令,支持硬件差异。
-
好处:提高代码灵活性,方便适配不同硬件型号或协议。
4. 性能调优
-
批量查询(如果硬件支持):
csharp
public async Task<HardwareResult[]> BatchQueryAsync(string[] instructions, CancellationToken cancellationToken = default)
{
await _semaphore.WaitAsync(cancellationToken);
try
{
// 模拟批量查询
var results = new HardwareResult[instructions.Length];
for (int i = 0; i < instructions.Length; i++)
{
await Task.Delay(10, cancellationToken); // 替换为实际批量 API
results[i] = new HardwareResult();
}
return results;
}
finally
{
_semaphore.Release();
}
}在 StartQueryAsync 中使用:
csharp
var results = await m_Hardware.BatchQueryAsync(new[] { "DAQREAD", "DAQREADADAPTERBOARD" }, _cts.Token);
ProcessBatchResults(results);好处:减少硬件访问次数,提高吞吐量。
-
线程池优化:
-
使用 Task.Run 运行采集任务,避免手动创建线程:
csharp
public async Task StartQueryAsync()
{
await Task.Run(async () =>
{
// 原 StartQueryAsync 逻辑
}, _cts.Token);
}
好处:利用线程池减少线程创建开销。
-
-
状态管理优化:
-
使用 Interlocked 操作更新标志位:
csharp
private int _isRunningFlag = 0;
private bool IsRunning
{
get => Interlocked.CompareExchange(ref _isRunningFlag, 0, 0) == 1;
set => Interlocked.Exchange(ref _isRunningFlag, value ? 1 : 0);
}
好处:确保线程安全的标志位更新。
-
5. 日志增强
在关键点添加详细日志:
csharp
private void HandleException(Exception ex, string message)
{
ExceptionDoEvnets(ex);
m_Log.Error($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] {Name}: {message}: {ex.Message}, StackTrace: {ex.StackTrace}");
SystemNotifEvent.HardErrorNotifEvent(this, $"{Name}: {message}", "");
}
private async Task RateQueryAsync()
{
m_Log.Info($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] Starting RateQuery for {Name}, ReadLooping={ReadLooping}");
// 原逻辑
}
好处:记录时间戳、硬件状态和堆栈信息,便于问题定位。
优化的详细说明
异步实现:
-
技术:使用 async/await 和 SemaphoreSlim,支持非阻塞硬件访问。
-
效果:减少线程阻塞,适合 IO 密集型操作,提高响应性。
-
适配性:异步方法可无缝对接现代硬件 API(如串口、TCP/IP)。
定时器优化:
-
技术:PeriodicTimer 提供异步定时,配合 CancellationToken 支持优雅取消。
-
效果:比 System.Timers.Timer 更轻量,减少资源占用,支持异步流程。
-
配置:通过 HardwareConfig.QueryIntervalMs 动态调整间隔(默认 100ms)。
硬件适配:
-
技术:通过 IHardware 接口和 HardwareConfig 类支持不同硬件配置。
-
效果:提高代码灵活性,适配同步/异步 API 和不同硬件协议。
-
示例:可配置 QueryInstruction 为特定硬件的指令(如 "READ_SENSOR")。
性能调优:
-
合并线程:单一异步任务替代两个线程,减少上下文切换。
-
批量查询:如果硬件支持,合并 DAQREAD 和 DAQREADADAPTERBOARD,减少 IO 开销。
-
线程池:使用 Task.Run 利用线程池,优化资源分配。
-
状态管理:Interlocked 确保标志位线程安全。
错误处理和日志:
-
统一异常处理:通过 HandleException 集中日志和通知。
-
详细日志:添加时间戳和堆栈信息,方便调试。
-
效果:提高系统健壮性和可维护性。
注意事项
-
定时器间隔:HardwareConfig.QueryIntervalMs 默认 100ms,需根据硬件响应时间测试调整(例如 50ms 或 200ms)。
-
硬件 API:需确认实际硬件 API 是否支持异步或批量查询,若不支持,可回退到同步实现。
-
取消机制:CancellationToken 确保优雅停止,但需测试取消后硬件状态是否正确重置。
-
性能测试:在高负载场景下测试采集频率、CPU 使用率和内存占用,确保优化效果。
-
日志存储:建议将日志写入文件或数据库,避免内存溢出。
示例使用
csharp
var config = new HardwareConfig { QueryIntervalMs = 50 }; // 调整为 50ms
m_Hardware = new Hardware(config);
await StartQueryAsync();
// 停止采集
await StopQueryAsync();
如果需要针对特定硬件 API(如串口、Modbus)或进一步性能调优(如连接池、缓存),请提供硬件细节或性能瓶颈描述,我可以提供更定制化的解决方案!




![P11246 [GESP202409 六级] 小杨和整数拆分-171主机测评](https://www.171host.com/wp-content/uploads/2026/11/20261108100631-6af049a75855c-220x150.png)