Async optimization

This commit is contained in:
2025-02-03 22:28:31 +01:00
parent 9283b04971
commit 241a9d114c
8 changed files with 133 additions and 104 deletions

View File

@@ -192,17 +192,16 @@ namespace AMWD.Protocols.Modbus.Serial
public Task StopAsync(CancellationToken cancellationToken = default)
{
Assertions();
return StopAsyncInternal(cancellationToken);
StopAsyncInternal();
return Task.CompletedTask;
}
private Task StopAsyncInternal(CancellationToken cancellationToken)
private void StopAsyncInternal()
{
_stopCts?.Cancel();
_serialPort.Close();
_serialPort.DataReceived -= OnDataReceived;
return Task.CompletedTask;
}
/// <summary>
@@ -215,7 +214,7 @@ namespace AMWD.Protocols.Modbus.Serial
_isDisposed = true;
StopAsyncInternal(CancellationToken.None).Wait();
StopAsyncInternal();
_serialPort.Dispose();
_stopCts?.Dispose();
@@ -332,7 +331,7 @@ namespace AMWD.Protocols.Modbus.Serial
responseBytes.AddRange(requestBytes.Take(2));
try
{
var coils = await Client.ReadCoilsAsync(unitId, firstAddress, count, cancellationToken);
var coils = await Client.ReadCoilsAsync(unitId, firstAddress, count, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
byte[] values = new byte[(int)Math.Ceiling(coils.Count / 8.0)];
for (int i = 0; i < coils.Count; i++)
@@ -371,7 +370,7 @@ namespace AMWD.Protocols.Modbus.Serial
responseBytes.AddRange(requestBytes.Take(2));
try
{
var discreteInputs = await Client.ReadDiscreteInputsAsync(unitId, firstAddress, count, cancellationToken);
var discreteInputs = await Client.ReadDiscreteInputsAsync(unitId, firstAddress, count, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
byte[] values = new byte[(int)Math.Ceiling(discreteInputs.Count / 8.0)];
for (int i = 0; i < discreteInputs.Count; i++)
@@ -410,7 +409,7 @@ namespace AMWD.Protocols.Modbus.Serial
responseBytes.AddRange(requestBytes.Take(2));
try
{
var holdingRegisters = await Client.ReadHoldingRegistersAsync(unitId, firstAddress, count, cancellationToken);
var holdingRegisters = await Client.ReadHoldingRegistersAsync(unitId, firstAddress, count, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
byte[] values = new byte[holdingRegisters.Count * 2];
for (int i = 0; i < holdingRegisters.Count; i++)
@@ -444,7 +443,7 @@ namespace AMWD.Protocols.Modbus.Serial
responseBytes.AddRange(requestBytes.Take(2));
try
{
var inputRegisters = await Client.ReadInputRegistersAsync(unitId, firstAddress, count, cancellationToken);
var inputRegisters = await Client.ReadInputRegistersAsync(unitId, firstAddress, count, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
byte[] values = new byte[count * 2];
for (int i = 0; i < count; i++)
@@ -492,7 +491,7 @@ namespace AMWD.Protocols.Modbus.Serial
LowByte = requestBytes[5],
};
bool isSuccess = await Client.WriteSingleCoilAsync(requestBytes[0], coil, cancellationToken);
bool isSuccess = await Client.WriteSingleCoilAsync(requestBytes[0], coil, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
if (isSuccess)
{
// Response is an echo of the request
@@ -531,7 +530,7 @@ namespace AMWD.Protocols.Modbus.Serial
LowByte = requestBytes[5]
};
bool isSuccess = await Client.WriteSingleHoldingRegisterAsync(requestBytes[0], register, cancellationToken);
bool isSuccess = await Client.WriteSingleHoldingRegisterAsync(requestBytes[0], register, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
if (isSuccess)
{
// Response is an echo of the request
@@ -591,7 +590,7 @@ namespace AMWD.Protocols.Modbus.Serial
});
}
bool isSuccess = await Client.WriteMultipleCoilsAsync(requestBytes[0], coils, cancellationToken);
bool isSuccess = await Client.WriteMultipleCoilsAsync(requestBytes[0], coils, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
if (isSuccess)
{
// Response is an echo of the request
@@ -648,7 +647,7 @@ namespace AMWD.Protocols.Modbus.Serial
});
}
bool isSuccess = await Client.WriteMultipleHoldingRegistersAsync(requestBytes[0], list, cancellationToken);
bool isSuccess = await Client.WriteMultipleHoldingRegistersAsync(requestBytes[0], list, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
if (isSuccess)
{
// Response is an echo of the request
@@ -705,7 +704,7 @@ namespace AMWD.Protocols.Modbus.Serial
try
{
var deviceInfo = await Client.ReadDeviceIdentificationAsync(requestBytes[0], category, firstObject, cancellationToken);
var deviceInfo = await Client.ReadDeviceIdentificationAsync(requestBytes[0], category, firstObject, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
var bodyBytes = new List<byte>();
@@ -855,5 +854,21 @@ namespace AMWD.Protocols.Modbus.Serial
}
#endregion Request Handling
/// <inheritdoc/>
public override string ToString()
{
var sb = new StringBuilder();
sb.AppendLine($"RTU Proxy");
sb.AppendLine($" {nameof(PortName)}: {PortName}");
sb.AppendLine($" {nameof(BaudRate)}: {(int)BaudRate}");
sb.AppendLine($" {nameof(DataBits)}: {DataBits}");
sb.AppendLine($" {nameof(StopBits)}: {StopBits}");
sb.AppendLine($" {nameof(Parity)}: {Parity}");
sb.AppendLine($" {nameof(Client)}: {Client.GetType().Name}");
return sb.ToString();
}
}
}

View File

@@ -31,8 +31,7 @@ namespace AMWD.Protocols.Modbus.Serial
private readonly Task _processingTask;
private readonly AsyncQueue<RequestQueueItem> _requestQueue = new();
// Only required to cover all logic branches on unit tests.
private bool _isUnitTest = false;
private readonly bool _isLinux;
#endregion Fields
@@ -41,6 +40,8 @@ namespace AMWD.Protocols.Modbus.Serial
/// </summary>
public ModbusSerialConnection(string portName)
{
_isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
if (string.IsNullOrWhiteSpace(portName))
throw new ArgumentNullException(nameof(portName));
@@ -268,7 +269,7 @@ namespace AMWD.Protocols.Modbus.Serial
try
{
// Get next request to process
var item = await _requestQueue.DequeueAsync(cancellationToken);
var item = await _requestQueue.DequeueAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
// Remove registration => already removed from queue
item.CancellationTokenRegistration.Dispose();
@@ -276,13 +277,13 @@ namespace AMWD.Protocols.Modbus.Serial
// Build combined cancellation token
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, item.CancellationTokenSource.Token);
// Wait for exclusive access
await _portLock.WaitAsync(linkedCts.Token);
await _portLock.WaitAsync(linkedCts.Token).ConfigureAwait(continueOnCapturedContext: false);
try
{
// Ensure connection is up
await AssertConnection(linkedCts.Token);
await _serialPort.WriteAsync(item.Request, linkedCts.Token);
await _serialPort.WriteAsync(item.Request, linkedCts.Token).ConfigureAwait(continueOnCapturedContext: false);
linkedCts.Token.ThrowIfCancellationRequested();
@@ -291,7 +292,7 @@ namespace AMWD.Protocols.Modbus.Serial
do
{
int readCount = await _serialPort.ReadAsync(buffer, 0, buffer.Length, linkedCts.Token);
int readCount = await _serialPort.ReadAsync(buffer, 0, buffer.Length, linkedCts.Token).ConfigureAwait(continueOnCapturedContext: false);
if (readCount < 1)
throw new EndOfStreamException();
@@ -322,7 +323,7 @@ namespace AMWD.Protocols.Modbus.Serial
_portLock.Release();
_idleTimer.Change(IdleTimeout, Timeout.InfiniteTimeSpan);
await Task.Delay(InterRequestDelay, cancellationToken);
await Task.Delay(InterRequestDelay, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
}
}
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
@@ -353,7 +354,7 @@ namespace AMWD.Protocols.Modbus.Serial
_serialPort.Close();
_serialPort.ResetRS485DriverStateFlags();
if (DriverEnabledRS485 && (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || _isUnitTest))
if (DriverEnabledRS485 && _isLinux)
{
var flags = _serialPort.GetRS485DriverStateFlags();
flags |= RS485Flags.Enabled;
@@ -361,7 +362,7 @@ namespace AMWD.Protocols.Modbus.Serial
_serialPort.ChangeRS485DriverStateFlags(flags);
}
using var connectTask = Task.Run(_serialPort.Open);
using var connectTask = Task.Run(_serialPort.Open, cancellationToken);
if (await Task.WhenAny(connectTask, Task.Delay(ReadTimeout, cancellationToken)) == connectTask)
{
await connectTask;
@@ -379,7 +380,7 @@ namespace AMWD.Protocols.Modbus.Serial
try
{
await Task.Delay(TimeSpan.FromSeconds(delay), cancellationToken);
await Task.Delay(TimeSpan.FromSeconds(delay), cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
}
catch
{ /* keep it quiet */ }