因此,我的C#任务延迟具有一种非常奇怪的行为,这使我发疯。
上下文:我正在使用C#.net通过R4852与我们的其中一台设备进行通信。该设备大约需要200毫秒才能完成每个命令,因此我在通信类中引入了250毫秒的延迟。
错误/不良行为:通讯类内部的延迟有时等待250毫秒,有时仅等待125毫秒。这是可重现的,并且当我增加延迟时会发生相同的行为。例如。如果我将延迟设置为1000毫秒,则第二个请求将仅等待875毫秒,因此又缺少了125毫秒。
仅当没有附加调试器时,才会发生此行为,并且仅在某些计算机上会发生。我们的生产部门将使用该软件的机器存在此问题,我现在正在使用的机器没有此问题。两者都运行Windows 10。
为何不时缺少125ms?
我已经了解到Task.Delay方法正在使用精度为15ms的计时器。这并不能解释丢失的125ms,因为它最多应该触发得太晚几毫秒而不是触发得早125m。
以下方法是我用来将命令排队到设备的方法。有一个信号量负责,因此一次只能执行一个命令(_requestSemapohre),因此只能处理一个请求。
public async Task<bool> Request(WriteRequest request)
{
await _requestSemaphore.WaitAsync(); // block incoming calls
await Task.Delay(Delay); // delay
Write(_connectionIdDictionary[request.Connection], request.Request); // write
if (request is WriteReadRequest)
{
_currentRequest = request as WriteReadRequest;
var readSuccess = await _readSemaphore.WaitAsync(Timeout); // wait until read of line has finished
_currentRequest = null; // set _currentRequest to null
_requestSemaphore.Release(); // release next incoming call
if (!readSuccess)
{
return false;
}
else
{
return true;
}
}
else
{
if (request is WriteWithDelayRequest)
{
await Task.Delay((request as WriteWithDelayRequest).Delay);
}
_requestSemaphore.Release(); // release next incoming call
return true;
}
}
以下代码是将请求发送到上述方法的方法的一部分。我删除了一些行以使其简短。基本的内容(请求和等待)仍然存在
// this command is the first command and will always have a proper delay of 1000ms
var request = new Communication.Requests.WriteRequest(item.Connection, item.Command);
await _translator.Request(request);
// this request is the second request that is missing 125ms
var queryRequest = new Communication.Requests.WriteReadRequest(item.Connection, item.Query); // query that is being sent to check if the value has been sent properly
if (await _translator.Request(queryRequest)) // send the query to the device and wait for response
{
if (item.IsQueryValid(queryRequest.Response)) // check result
{
item.Success = true;
}
}
我要发送给此方法的第一个请求是
WriteRequest
,第二个请求是WriteReadRequest
。在使用名为Device Monitoring Studio的软件监视串行通信时查看串行端口通信时,我发现了此行为。
这是实际串行通讯的屏幕截图。在这种情况下,我使用了1000ms的延迟。您可以看到
sens0002
命令在执行之前有1秒的延迟。下一个命令/查询sens?
仅具有875毫秒的延迟。该屏幕快照是在未附加调试器时拍摄的。这是另一个屏幕截图。延迟再次设置为1000ms,但这一次连接了调试器。如您所见,第一个和第二个命令现在都具有大约1000ms的延迟。
在下面的两个屏幕截图中,您可以看到相同的行为,但有250ms的延迟(降低到125ms)。第一个屏幕快照未附加调试器,第二个屏幕快照已附加调试器。在第二个屏幕截图中,您还可以看到35ms的漂移很安静,但仍远未达到之前所缺少的125ms。
那我到底在看什么呢?快速而肮脏的解决方案是将延迟增加到1000ms,这样就不再是问题了,但我宁愿理解为什么会发生此问题以及如何正确解决它。
干杯!
最佳答案
据我所知,您的时间被打印为上一时间的增量。条目。
在125 / 875ms的情况下,您有8个中间条目,每条大约15ms(总和大约120ms)
在250 / 1000ms的情况下,您有8个中间条目,每个中间条目大约5ms(总和大约40ms),而实际数字更像是215 / 960ms。
因此,如果加上这些中间延迟,据我所知,最终的完整延迟大致相同。
为只想在问题标题上回答是/否的每个人回答问题:The First Rule of Programming: It's Always Your Fault
可以假设Task.Delay
至少覆盖了指定的时间量(由于时钟分辨率而可能会更长)。因此,如果似乎所用的时间跨度较小,则用于测试实际延迟的方法可能会出错。