2012-01-14 6 views
14

メッセージングクライアントのテストアプリケーションでは、サーバーのフラッディングを避けるために、プロデューサスレッドを調整する必要があります。スレッドを1ミリ秒未満で一時停止

転送速度は1秒あたり約25,000メッセージ(メッセージあたり40マイクロ秒)であるため、スリープ(1)による遅延は非常に長くなります。

How to make thread sleep less than a millisecond on Windowsには、Windows APIに関連する情報が含まれています。 Delphiのコードスニペット、クラス、ライブラリはありますか?

私が15以下の異なる値との睡眠は、異なる転送速度(Windows Vistaの)を与えることがわかったベンズ解答後

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) 

スリープ:すべての20件のメッセージの後に

スリープ(1) (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

+0

@Serg、AFAIK circa 15 ms – OnTheFly

答えて

21

を絞ることなく、

と値を待って忙しいの下限から20メッセージを送信した後、1ミリ秒のために寝ますか?

システムタイマー以外のハードウェア割り込みがない限り、スケジューラークォンタム未満のスリープ状態はできません。あなたがリンクした質問の答えを読んで、提案されたアプローチが実際には機能しない理由を説明します。

この方法でも、1ms以上スリープ状態になることや、メッセージが瞬間的に送信されないため、動作全体が1msより長くかかることがあり、全体の速度が低下します。だから、

、定数20

+3

Windowsでは、QueryPerformanceCounter(http://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx)を精度として推奨しますクロックソース(約0.5マイクロ秒の分解能まで)。 – Crashworks

+0

+1、間違いなく最良のアプローチ - 短い遅延の必要性をなくす。 –

12

1を使用しない、高精度クロック・ソースにあなたが目を覚ますたびに検査し、経過時間に基づいて送信するためにどのように多くのメッセージを計算)は、現在の時刻を取得します。

2)送信したメッセージの数とそれ以降の経過時間に基づいて、送信するメッセージの数を計算します。

3)多くのメッセージを送信します。

4)可能な限り少ない量で眠ります。

5)が代わりに睡眠の1

0

に進み、なぜ別のスレッド/プロセスがプロセッサではbashを持たせるためにTTheard.Yieldを使用していませんか?

+0

..準備が整っているスレッドが他にないかもしれません。その場合、何もしません。 –

3

他の人からも言われているように、短い時間ではスリープできません(スリープ(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

+0

TStopWatchはOS/Xとの互換性にも優れています。 – gabr

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ナノ秒

関連する問題