.net 线程,休眠少于1毫秒

u5i3ibmn  于 2023-03-13  发布在  .NET
关注(0)|答案(6)|浏览(140)

我想在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);
 }

我很乐意听听你对那件事的意见。

xmd2e60i

xmd2e60i1#

一个sleep调用通常会阻塞超过1毫秒的时间(这取决于操作系统和系统,但根据我的经验,Thread.Sleep(1)的阻塞时间通常在12- 15 ms之间)。
Windows通常不是作为real-time operating system设计的。这种类型的控制通常不可能在普通(桌面/服务器)版本的Windows上实现。
你能得到的最接近的方法通常是旋转和消耗CPU周期,直到你达到你想要的等待时间(用高性能计数器测量)。然而,这是相当可怕的-你会消耗掉整个CPU,即使这样,你可能会得到操作系统的preempted有时和有效的“睡眠”超过1 ms...

xsuvu9jc

xsuvu9jc2#

下面的代码肯定会提供一种更精确的阻塞方式,而不是调用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();
}
smdnsysy

smdnsysy3#

"为什么"
通常,一台机器上的CPU和内核数量非常有限--如果是独立的执行单元,则数量很少。
另一方面,有许多进程和更多的线程。每个线程需要一些处理器时间,这是由Windows核心进程内部分配的。通常Windows阻止所有线程,并给特定线程一定量的CPU核心时间,然后将上下文切换到其他线程。
当你调用Thread.Sleep时,不管你把Windows给线程的整个时间间隔杀得多短,因为没有理由简单地等待它,上下文会立即切换。当Windows下次给你的线程一些CPU时,它可能需要几毫秒。

使用什么?

或者,您可以使用spin your CPU,spinning,这不是一件糟糕的事情,它可能非常有用。例如,它在 System.Collections.Concurrent 命名空间中使用了很多非阻塞集合,例如:

SpinWait sw = new SpinWait();
sw.SpinOnce();
zwghvu4y

zwghvu4y4#

使用Thread.Sleep(1)Thread.Sleep(0)的大多数合理原因都涉及到相当高级的线程同步技术。就像Reed说的,使用常规技术不会得到所需的分辨率。我不确定你想要完成的是什么,但是我想我可以假设你想让一个动作以1毫秒的间隔发生。如果是这样的话,那么看看multimedia timers。它们可以提供低至1ms的分辨率。不幸的是,.NET框架中没有内置的API(据我所知)可以利用这个Windows特性。但是你可以使用互操作层直接调用Win32 API。甚至有用C#做这件事的例子。

2fjabf4q

2fjabf4q5#

在过去的好日子里,当需要亚毫秒分辨率时,您会使用Win32的“QueryPerformanceTimer”API。
似乎有更多关于这个主题的信息在代码项目:http://www.codeproject.com/KB/cs/highperformancetimercshar.aspx
这将不允许您以ReedCopsey指出的相同分辨率“Sleep()”。

**编辑:**正如Reed Copsey和Brian Gideon所指出的,QueryPerformanceTimer在.NET中已被Stopwatch所取代

eni9jsuy

eni9jsuy6#

我在寻找和OP一样的东西,并且设法找到了一个适合我的答案。我很惊讶其他的答案都没有提到这一点。
调用Thread.Sleep()时,可以使用以下两种重载之一:一个以毫秒数表示的int值,或一个TimeSpan值。
TimeSpan的构造函数有很多重载。其中一个是一个long,表示TimeSpan所代表的tick数。一个tick比1ms短很多。事实上,TimeSpan文档的另一部分给出了10000个tick在1ms内发生的例子。
因此,我认为这个问题最接近的答案是,如果您希望Thread.Sleep的时间少于1ms,那么您应该创建一个时间间隔少于1ms的TimeSpan,然后将其传递给Thread.Sleep()。

相关问题