因此,我的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毫秒的延迟。该屏幕快照是在未附加调试器时拍摄的。
c# - .net中的Task.Delay提前触发125ms-LMLPHP

这是另一个屏幕截图。延迟再次设置为1000ms,但这一次连接了调试器。如您所见,第一个和第二个命令现在都具有大约1000ms的延迟。
c# - .net中的Task.Delay提前触发125ms-LMLPHP

在下面的两个屏幕截图中,您可以看到相同的行为,但有250ms的延迟(降低到125ms)。第一个屏幕快照未附加调试器,第二个屏幕快照已附加调试器。在第二个屏幕截图中,您还可以看到35ms的漂移很安静,但仍远未达到之前所缺少的125ms。
c# - .net中的Task.Delay提前触发125ms-LMLPHP
c# - .net中的Task.Delay提前触发125ms-LMLPHP

那我到底在看什么呢?快速而肮脏的解决方案是将延迟增加到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至少覆盖了指定的时间量(由于时钟分辨率而可能会更长)。因此,如果似乎所用的时间跨度较小,则用于测试实际延迟的方法可能会出错。

08-19 01:11