2012-01-14 88 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納秒