2012-01-14 91 views
14

在消息传递客户端测试应用程序中,需要限制生产者线程以避免泛滥服务器。将线程暂停时间少于1毫秒

由于传输速率是大约每秒25000消息(每个消息40微秒),引起睡眠(1)将时间太长的延迟。

How to make thread sleep less than a millisecond on Windows包含一些与Windows API相关的信息。是否有Delphi的代码片段,类或库?


继BENS答案,我发现不同的值,即睡眠低于15也给出了不同的传输速率(Windows Vista中):

睡眠(1)每20封邮件后:

00:02 tx/rx 25740/3705 12831/1846 msgs/sec (77/541 microsecs/msg) 
00:04 tx/rx 53101/7405 13255/1848 msgs/sec (75/541 microsecs/msg) 
00:06 tx/rx 79640/11288 13260/1879 msgs/sec (75/532 microsecs/msg) 
00:08 tx/rx 104520/14562 13055/1818 msgs/sec (76/550 microsecs/msg) 
00:10 tx/rx 130760/18829 13066/1881 msgs/sec (76/531 microsecs/msg) 

睡眠(5)每20条消息之后:

00:02 tx/rx 7640/3622 3812/1807 msgs/sec (262/553 microsecs/msg) 
00:04 tx/rx 14660/10794 3661/2695 msgs/sec (273/371 microsecs/msg) 
00:06 tx/rx 21480/18171 3577/3026 msgs/sec (279/330 microsecs/msg) 
00:08 tx/rx 28140/25642 3515/3203 msgs/sec (284/312 microsecs/msg) 
00:10 tx/rx 34980/32692 3496/3267 msgs/sec (286/306 microsecs/msg) 

在阅读评论ab之后,这是意外的出去忙等待

,值没有节流

00:02 tx/rx 44065/494 21988/246 msgs/sec (45/4065 microsecs/msg) 
00:04 tx/rx 90493/756 22595/188 msgs/sec (44/5319 microsecs/msg) 
00:06 tx/rx 142982/907 23810/151 msgs/sec (41/6622 microsecs/msg) 
00:08 tx/rx 192562/1144 24055/142 msgs/sec (41/7042 microsecs/msg) 
00:10 tx/rx 237294/1395 23717/139 msgs/sec (42/7194 microsecs/msg) 
+0

您可以实现只忙等待小于1毫秒,无法入睡。 – kludg 2012-01-14 07:42:00

+0

@Serg,AFAIK大约15 ms – OnTheFly 2012-01-14 08:15:57

回答

21

下限发送20条信息,然后睡了1毫秒?

除了系统定时器之外,你不能睡眠的时间少于调度器的量程,除非你有硬件中断。阅读您链接的问题中的答案,他们解释为什么建议的方法实际上不起作用。即使这种方法

你可能会对睡眠时间超过1ms,或者因为消息不被立即发送,整个操作过程一定会需要更长的时间超过1ms,降低了整体速度。

所以,每次你醒来时检查精密时钟源,计算有多少要发送的消息基于经过的时间,不使用恒定的20

+3

在Windows上,我建议使用QueryPerformanceCounter(http://msdn.microsoft.com/zh-cn/library/windows/desktop/ms644904(v=vs.85).aspx)作为精度时钟源(低至大约半微秒的分辨率)。 – Crashworks 2012-01-14 12:08:12

+0

+1,绝对是最好的方法 - 设计出对短暂延迟的需求。 – 2012-01-14 12:30:23

12

1)获取当前时间。

2)计算你需要多少邮件发送基于有多少你已经发送了多少时间已经过去至今。

3)发送很多消息。

4)尽量少量睡觉。

5)转到步骤1.

0

而是睡觉的,为什么不使用TTheard.Yield让另一个线程/进程必须在该处理器的庆典?

+0

..可能没有任何其他准备就绪的线程,在这种情况下,Yield不会执行任何操作。 – 2012-01-16 06:06:09

3

正如其他人所说,你不能睡短的时间量(甚至睡眠(1)是不可靠的 - 它可以很容易地睡远远超过1毫秒)。

你最好的赌注是计算时间为下一个消息,然后执行一个忙等待 - 环和检查时间 - 直到出现所需的时间。下面是一个完整的解决方案和一个小测试框架。

program SendEquidistantMessages; 

{$APPTYPE CONSOLE} 

{$R *.res} 

uses 
    Windows, SysUtils; 

procedure SendMessage(msgNum: integer); 
begin 
    // send the message here 
end; 

procedure WaitUntil(nextMsgTime: int64); 
var 
    currTime: int64; 
begin 
    repeat 
    QueryPerformanceCounter(currTime); 
    if currTime >= nextMsgTime then 
     break; //repeat 
    asm pause; end; 
    until false; 
end; 

procedure SendMessages(numMsg, msgPerSec: integer); 
var 
    iMsg  : integer; 
    nextMsgTime: int64; 
    perfFreq : int64; 
    prevMsg : int64; 
    startTime : int64; 

begin 
    Assert(QueryPerformanceFrequency(perfFreq)); 
    Assert(QueryPerformanceCounter(startTime)); 
    for iMsg := 1 to numMsg do begin 
    WaitUntil(Round(startTime + iMsg/msgPerSec * perfFreq)); 
    SendMessage(iMsg); 
    end; 
end; 

var 
    time: cardinal; 

begin 
    try 
    time := GetTickCount; 
    SendMessages(20000, 5000); 
    time := GetTickCount-time; 
    Writeln('20.000 messages sent in ', time/1000:4:1, ' sec; ', 
     'required rate = 5000 msg/sec, real rate = ', 20000/(time/1000):6:1, ' msg/sec'); 
    Readln; 
    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 
end. 
+1

如果适用(使用最新版本的Delphi),我主张使用'Diagnostic.TStopWatch'来监控流逝的时间:它允许访问高分辨率定时器(如果有的话)。 – menjaraz 2012-01-14 09:20:03

+0

TStopWatch也适用于OS/X兼容性 - 好点! – gabr 2012-01-14 09:34:35

0

有一个线程Sleep Less Than One Millisecond处理类似的问题。 我已经给出了关于如何让线程随时休眠的一些细节。这当然也包括在微秒范围内的睡眠。 主题:由服务线程创建定时事件,等待功能

更多细节,也可以在Windows Timestamp Project

0

一个解决方法是获取当前时间与纳米秒,然后你想睡觉的时候此外,它发现(等待)和循环,直到当前时间(具有纳米秒)变得比您计算出的时间时,则存在说明这一方法:

public void wait(long nano){ 
    long t= System.nanoTime(); 
    t+= nano; 
    while(System.nanoTime()<t); 
} 

注意的是: 1秒= 1000毫秒= 1000000微秒= 1000000000纳秒

所以

1毫秒= 1000000纳秒