2

我在 C# 中有一个轮询循环,平均需要每 100 微秒轮询一次 <EDIT>(当然,由于核心短缺,Windows 没有进行过多的抢占式线程上下文切换)</EDIT>

由于没有时间重新安排,Sleep(1) 不会这样做。

所以我决定专用一个线程(实际上,在设置亲和力时,一个核心)并使用 Thread.SpinWait 为每次迭代的一组周期。虽然这很好用,但它消耗了不必要的电量。100 微秒足以让 CPU 暂停(但不足以让线程从调度程序中临时删除,因为 Windows 时间片会很长)。

相反,我正在考虑使用 Intel PAUSE 指令,但我不确定它是否会触发 Intel CPU 暂停硬件线程。英特尔声称它可以保存功率并且应该在自旋循环中使用,但由于暂停时间长达 100 微秒,我真的希望内核进入 C1 模式睡眠。

有任何想法吗?

编辑:我正在轮询第三方 API,因此没有要阻止的同步事件。

4

2 回答 2

2

鉴于您的等待时间很长,您可能会发现SSE3 内存区域监视器在节能方面效率更高,但是,它并不是真正设计为阻塞自旋等待,而是作为警报等待,但仍可能证明是一种可行的替代方案。

然而,在 C# 中获取它需要一个外部 DLL,它提供了 C++ 内部函数(_mm_mwait_mm_monitor)的接口。

于 2012-08-07T14:14:55.320 回答
2

自然地,使用同步原语和计时器是避免 CPU/耗电量大的忙等待的首选方法。但是,如果您需要如此频繁地轮询 - 至少在用户模式下,无法通过常规方式实现这一点。

您可以做的一件简单的事情是pause在循环中包含一条 CPU 指令。在 MSVC 中,它是通过内部YieldProcessor()方法实现的。

除此之外 - 可能仅在内核模式编程中。在那里您可以使用高精度多媒体计时器。

编辑:

关于SetWaitableTimer. 这可能是一种选择。与“传统的”Win32 等待函数(例如SleepWaitForSingleObject)不同,它使用高精度超时作为参数。

然而,用户模式定时器本质上是异步的。让我们假设计时器以高精度激活(这并不明显,“传统”Win32 等待函数精确到刻度量,大约几十毫秒)。计时器激活后 - 它释放适当的等待线程。但是线程调度程序不必立即将此线程附加到执行中——它可能会等待下一个时间片。如果有并发线程,甚至会更多地延迟线程执行。

总之:这个想法似乎值得一试。但是,如果这或多或少等同于 using ,我不会感到惊讶Sleep

于 2012-08-07T13:25:38.643 回答