gpt4 book ai didi

C# 为什么定时器频率非常低?

转载 作者:可可西里 更新时间:2023-11-01 07:49:43 45 4
gpt4 key购买 nike

System.Timers.TimerSystem.Threading.Timer 的触发时间间隔与请求的时间间隔有很大不同。例如:

new System.Timers.Timer(1000d / 20);

生成每秒触发 16 次而不是 20 次的计时器。

为了确保太长的事件处理程序不会产生副作用,我编写了这个小测试程序:

int[] frequencies = { 5, 10, 15, 20, 30, 50, 75, 100, 200, 500 };

// Test System.Timers.Timer
foreach (int frequency in frequencies)
{
int count = 0;

// Initialize timer
System.Timers.Timer timer = new System.Timers.Timer(1000d / frequency);
timer.Elapsed += delegate { Interlocked.Increment(ref count); };

// Count for 10 seconds
DateTime start = DateTime.Now;
timer.Enabled = true;
while (DateTime.Now < start + TimeSpan.FromSeconds(10))
Thread.Sleep(10);
timer.Enabled = false;

// Calculate actual frequency
Console.WriteLine(
"Requested frequency: {0}\nActual frequency: {1}\n",
frequency, count / 10d);
}

输出看起来像这样:

要求:5 赫兹;实际:4.8 赫兹
要求:10 赫兹;实际:9.1 赫兹
要求:15 赫兹;实际:12.7 赫兹
要求:20 赫兹;实际:16 赫兹
要求:30 赫兹;实际:21.3 赫兹
要求:50 赫兹;实际:31.8 赫兹
要求:75 赫兹;实际:63.9 赫兹
要求:100 赫兹;实际:63.8 赫兹
要求:200 赫兹;实际:63.9 赫兹
要求:500 赫兹;实际:63.9 赫兹

实际频率与请求频率的偏差高达 36%。 (而且显然不能超过 64 Hz。)鉴于 Microsoft 推荐此计时器是因为它比 System.Windows.Forms.Timer“更准确”,这让我感到困惑。

顺便说一句,这些不是随机偏差。它们每次都是相同的值。另一个计时器类 System.Threading.Timer 的类似测试程序显示了完全相同的结果。

在我的实际程序中,我需要以每秒 50 个样本的精确度收集测量值。这应该还不需要实时系统。每秒获取 32 个样本而不是 50 个样本是非常令人沮丧的。

有什么想法吗?

@克里斯:你是对的,间隔似乎都是 1/64 秒左右的整数倍。顺便说一句,在事件处理程序中添加 Thread.Sleep(...) 没有任何区别。这是有道理的,因为 System.Threading.Timer 使用线程池,因此每个事件都在空闲线程上触发。

最佳答案

如果您使用 winmm.dll,您可以使用更多的 CPU 时间,但可以更好地控制。

这里是您修改为使用 winmm.dll 计时器的示例

const String WINMM = "winmm.dll";
const String KERNEL32 = "kernel32.dll";

delegate void MMTimerProc (UInt32 timerid, UInt32 msg, IntPtr user, UInt32 dw1, UInt32 dw2);

[DllImport(WINMM)]
static extern uint timeSetEvent(
UInt32 uDelay,
UInt32 uResolution,
[MarshalAs(UnmanagedType.FunctionPtr)] MMTimerProc lpTimeProc,
UInt32 dwUser,
Int32 fuEvent
);

[DllImport(WINMM)]
static extern uint timeKillEvent(uint uTimerID);

// Library used for more accurate timing
[DllImport(KERNEL32)]
static extern bool QueryPerformanceCounter(out long PerformanceCount);
[DllImport(KERNEL32)]
static extern bool QueryPerformanceFrequency(out long Frequency);

static long CPUFrequency;

static int count;

static void Main(string[] args)
{
QueryPerformanceFrequency(out CPUFrequency);

int[] frequencies = { 5, 10, 15, 20, 30, 50, 75, 100, 200, 500 };

foreach (int freq in frequencies)
{
count = 0;

long start = GetTimestamp();

// start timer
uint timerId = timeSetEvent((uint)(1000 / freq), 0, new MMTimerProc(TimerFunction), 0, 1);

// wait 10 seconds
while (DeltaMilliseconds(start, GetTimestamp()) < 10000)
{
Thread.Sleep(1);
}

// end timer
timeKillEvent(timerId);

Console.WriteLine("Requested frequency: {0}\nActual frequency: {1}\n", freq, count / 10);
}

Console.ReadLine();
}

static void TimerFunction(UInt32 timerid, UInt32 msg, IntPtr user, UInt32 dw1, UInt32 dw2)
{
Interlocked.Increment(ref count);
}

static public long DeltaMilliseconds(long earlyTimestamp, long lateTimestamp)
{
return (((lateTimestamp - earlyTimestamp) * 1000) / CPUFrequency);
}

static public long GetTimestamp()
{
long result;
QueryPerformanceCounter(out result);
return result;
}

这是我得到的输出:

Requested frequency: 5
Actual frequency: 5

Requested frequency: 10
Actual frequency: 10

Requested frequency: 15
Actual frequency: 15

Requested frequency: 20
Actual frequency: 19

Requested frequency: 30
Actual frequency: 30

Requested frequency: 50
Actual frequency: 50

Requested frequency: 75
Actual frequency: 76

Requested frequency: 100
Actual frequency: 100

Requested frequency: 200
Actual frequency: 200

Requested frequency: 500
Actual frequency: 500

希望这对您有所帮助。

关于C# 为什么定时器频率非常低?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/416522/

45 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com