线程.睡眠时间小于1毫秒
本文关键字:小于 1毫秒 时间 线程 | 更新日期: 2023-09-27 17:58:41
我想用小于1毫秒的时间调用线程睡眠。我读到thread.Sleep
和Windows操作系统都不支持这一点。
解决方案是什么?
对于所有想知道我为什么需要这个的人:我正在做一个压力测试,想知道我的模块每秒能处理多少条消息。所以我的代码是:
// Set the relative part of Second hat will be allocated for each message
//For example: 5 messages - every message will get 200 miliseconds
var quantum = 1000 / numOfMessages;
for (var i = 0; i < numOfMessages; i++)
{
_bus.Publish(new MyMessage());
if (rate != 0)
Thread.Sleep(quantum);
}
我很乐意听听你对此的意见。
你不能这么做。一个睡眠调用的阻塞时间通常会超过一毫秒(这取决于操作系统和系统,但根据我的经验,Thread.Sleep(1)
往往会阻塞12-15毫秒)。
一般来说,Windows并不是作为实时操作系统设计的。这种类型的控制通常不可能在Windows的正常(桌面/服务器)版本上实现。
你能得到的最接近的通常是旋转和消耗CPU周期,直到你达到你想要的等待时间(用高性能计数器测量)。然而,这是非常可怕的——你会吃掉整个CPU,即使这样,你也可能有时被操作系统抢占,并有效地"睡眠"超过1毫秒。。。
下面的代码肯定会提供一种更精确的阻塞方式,而不是调用Thread.Sleep(x);
(尽管此方法会阻塞线程,而不是将其置于睡眠)。下面我们将使用StopWatch
类来衡量我们需要保持循环和阻塞调用线程的时间。
using System.Diagnostics;
private static void NOP(double durationSeconds)
{
var durationTicks = Math.Round(durationSeconds * Stopwatch.Frequency);
var sw = Stopwatch.StartNew();
while (sw.ElapsedTicks < durationTicks)
{
}
}
示例用法,
private static void Main()
{
NOP(5); // Wait 5 seconds.
Console.WriteLine("Hello World!");
Console.ReadLine();
}
为什么
通常,一台机器上的CPU和内核数量非常有限——如果是独立的执行单元,则只能得到一小部分。
另一方面,还有许多进程和更多的线程。每个线程都需要一些处理器时间,这些时间由Windows核心进程内部分配。通常,Windows会阻塞所有线程,并为特定线程提供一定的CPU核心时间,然后将上下文切换到其他线程。
当你调用Thread.Sleep时,无论你杀死Windows给线程的整个时间跨度有多小,因为没有理由简单地等待它,上下文会立即切换。当Windows下次给线程一些CPU时,可能需要几毫秒的时间。
使用什么
或者,你可以旋转你的CPU,旋转不是一件可怕的事情,而且非常有用。例如,它在System.Collections.Concurrent命名空间中大量使用非阻塞集合,例如:
SpinWait sw = new SpinWait();
sw.SpinOnce();
使用Thread.Sleep(1)
或Thread.Sleep(0)
的大多数正当理由都涉及相当高级的线程同步技术。正如里德所说,使用传统技术无法获得所需的分辨率。我不确定你想完成什么,但我想我可以假设你想让一个动作以1毫秒的间隔发生。如果是这样的话,看看多媒体定时器。它们可以提供低至1ms的分辨率。不幸的是,.NET框架中没有内置API(我知道)来利用此Windows功能。但是您可以使用互操作层直接调用Win32 API。甚至在C#中也有这样的例子。
在过去的好日子里,当需要毫秒以下的分辨率时,您会使用Win32的"QueryPerformanceTimer"API。
代码项目上似乎有更多关于这个主题的信息:http://www.codeproject.com/KB/cs/highperformancetimercshar.aspx
这将不允许您以Reed Copsey指出的相同分辨率"Sleep()"。
编辑:正如Reed Copsey和Brian Gideon所指出的,QueryPerformanceTimer已被.NET 中的Stopwatch
所取代
我一直在寻找与OP相同的东西,并设法找到了一个适合我的答案。我很惊讶其他答案都没有提到这一点。
调用Thread.Sleep()时,可以使用两个重载之一:一个是以毫秒为单位的int,或者一个是TimeSpan。
TimeSpan的构造函数又有许多重载。其中之一是表示TimeSpan所代表的刻度数的单个长刻度。一个刻度远小于1ms。事实上,TimeSpan文档的另一部分给出了一个在1ms内发生10000次滴答声的例子。
因此,我认为最接近这个问题的答案是,如果你想要Thread.Sleep小于1ms,你会创建一个TimeSpan,其刻度小于1ms的刻度,然后将其传递给Thread.Sleeep().