C# 如何平均每20毫秒*触发一次事件*?内置定时器“;“爬行”;

C# 如何平均每20毫秒*触发一次事件*?内置定时器“;“爬行”;,c#,timer,C#,Timer,我正在编写一个RTP服务器来发布PCMA wave文件。它需要每20毫秒泵送一次数据(平均值——任何一个泵的数据量都可能是20毫秒左右,但必须在20毫秒时进行平均) 我当前的实现使用了一个,但是事件每20毫秒触发一次,所以它会逐渐消失 有更好的方法吗?目前我能想到的唯一方法是在计时器开始爬行时动态调整计时器的内部,以便使其恢复正常 示例代码 输出: 1002 2001 3002 4003 5003 6005 7006 8007 9007 10017 11018 12019 13019 14020

我正在编写一个RTP服务器来发布PCMA wave文件。它需要每20毫秒泵送一次数据(平均值——任何一个泵的数据量都可能是20毫秒左右,但必须在20毫秒时进行平均)

我当前的实现使用了一个,但是事件每20毫秒触发一次,所以它会逐渐消失

有更好的方法吗?目前我能想到的唯一方法是在计时器开始爬行时动态调整计时器的内部,以便使其恢复正常

示例代码 输出:

1002
2001
3002
4003
5003
6005
7006
8007
9007
10017
11018
12019
13019
14020 <-- By this point we have creeped over 20 ms in just 14 iterations :(
1002
2001
3002
4003
5003
6005
7006
8007
9007
10017
11018
12019
13019

14020首先:我永远不会让它精确,因为只要你在标准Windows上运行,你的程序就永远不会完全控制CPU的工作,因为它不是实时操作系统。试想一下,一个反病毒程序启动了,垃圾收集器冻结了你的线程,在一旁玩游戏

也就是说你也许可以补偿一点

当处理程序启动时,暂停计时器,记录当前时间,执行操作,根据处理程序的开始和执行操作所用的时间将时间间隔设置为所需的时间间隔,从而更新时间间隔

这样可以更好地控制爬行。例外情况可能是,动作所需时间比间隔长,以及间隔应包含动作时间还是介于动作之间的时间


根据我的经验,你不能依靠任何计时器来精确地获得如此小的间隔(20毫秒),但补偿蠕变会有很大帮助。

你可以使用秒表来测量时间,但它没有回调功能


您可以使用Windows多媒体计时器。它涉及一些WinAPI,但所有细节都在这里提供。

仅供参考,您要查找的术语是漂移:-)@Cameron谢谢-我写这个问题时英国时间早上5点;-)WinAPI有一个解决方案,可等待计时器。不过,我认为没有.NET包装器。@Ben,我可以p/调用它吗?您可以添加几个链接作为答案吗?@RB.:您可以p/invoke函数来访问它,但是.NET的消息循环不支持等待句柄。在典型的C/C++应用程序中,使用
MsgWaitForMultipleObjects
替换
GetMessage
PeekMessage
非常简单。NET的消息循环非常奇特,并且与一系列其他Windows窗体功能(如消息过滤器)交织在一起,因此替换整个功能并不切实可行。它的核心是
GetMessage
,因此如果我们能够编辑它,升级它将很容易。但它是System.Windows.Forms.dllYeah的一部分——这就是我说动态调整计时器间隔时的意思。实际上,您可以在不暂停计时器的情况下执行此操作-只需添加一个处理程序,该处理程序的任务是计算出下一个适当的间隔,并设置
((计时器)发送器)。间隔-=漂移
。如果您不暂停计时器(或者更确切地说触发处理程序)如果执行操作的时间长于间隔,并且当有一个线程执行工作,而多个线程执行相同的工作时,计时器再次滴答作响,那么您可能会进入竞争状态……好的观点——我将围绕该场景进行测试。在实践中,如果泵送数据的时间间隔超过了一个计时器,我就会遇到更大的问题,因为我永远无法及时为客户提供服务!再次强调:您正在做的工作可能不会花费太多时间,但线程可能无法运行,因为其他线程获得CPU时间我正在通过UDP传输数据,并且客户端负责在数据包按顺序到达时对其进行分类,所以这应该是好的(事实上,这就是我正在寻找的行为)-我只需要确保我在这方面进行了一些测试。
1002
2001
3002
4003
5003
6005
7006
8007
9007
10017
11018
12019
13019
14020 <-- By this point we have creeped over 20 ms in just 14 iterations :(