0

マルチスレッド サーバー アプリケーションがあります。このアプリケーションは、ソケットからデータを受け取り、パッケージのアンパック、データ キューへの追加など、これらのデータを処理します。機能は次のとおりです。この関数は頻繁に呼び出されます。select ステートメントがあり、データがあることがわかった場合は、この関数を呼び出して受信します):

         //the main function used to receive 
         //file data from clients
         void service(void){
              while(1){
                   ....
                   struct timeval timeout;
                   timeout.tv_sec = 3;

                   ...
                   ret = select(maxFd+1, &read_set, NULL, NULL, &timeout);
                   if (ret > 0){
                       //get socket from SocketsMap
                       //if fd in SocketsMap and its being set
                       //then receive data from the socket
                       receive_data(fd);
                   }
              }
         } 

         void receive_data(int fd){
              const int ONE_MEGA = 1024 * 1024;

              //char *buffer = new char[ONE_MEGA]; consumes much less CPU
              char buffer[ONE_MEGA]; // cause high CPU 
              int readn = recv(fd, buffer, ONE_MEGA, 0);

              //handle the data
         }

上記は CPU を消費しすぎることがわかりました。通常は 80% から 90% ですが、代わりにヒープからバッファーを作成すると、CPU は 14% しかありません。なんで?

[更新]
コードを追加

[更新 2]
最も奇妙なことは、別の単純なデータ受信サーバーとクライアントも作成したことです。サーバーは、ソケットからデータを受信して​​破棄するだけです。どちらのタイプのスペース割り当てもほぼ同じように機能し、CPU 使用率に大きな違いはありません。問題のあるマルチスレッド サーバー アプリケーションでは、プロセス スタック サイズを 30M にリセットしても、配列を使用すると問題が発生しますが、ヒープから割り当てることで解決します。どうしてか分かりません。

「sizeof(buffer)」については、ご指摘ありがとうございます。ただし、私のアプリケーションでは sizeof(buffer) を使用せず、代わりに ONE_MEGA (1024*1024) を使用しているため、問題ではないことは 100% 確信しています。 .

ところで、役に立つかどうかはわかりませんが、もう1つ言及する必要があります。配列を「char buffer[1024];」などの小さい配列に置き換えると、CPU 使用率が大幅に低下します。

[update3]
すべてのソケットがノンブロッキング モードです。

4

3 に答える 3

3

私はちょうどこれを書いた:

#include <iostream>
#include <cstdio>

using namespace std;

static __inline__ unsigned long long rdtsc(void)
{
    unsigned hi, lo;
    __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
    return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
}

const int M = 1024*1024;

void bigstack()
{
    FILE *f = fopen("test.txt", "r");
    unsigned long long time;
    char buffer[M];

    time = rdtsc();
    fread(buffer, M, 1, f);
    time = rdtsc() - time;
    fclose(f);
    cout << "bs: Time = " << time / 1000 << endl;
}


void bigheap()
{
    FILE *f = fopen("test.txt", "r");
    unsigned long long time;
    char *buffer = new char[M];

    time = rdtsc();
    fread(buffer, M, 1, f);
    time = rdtsc() - time;
    delete [] buffer;
    fclose(f);
    cout << "bh: Time = " << time / 1000 << endl;
}



int main()
{
    for(int i = 0; i < 10; i++)
    {
    bigstack();
    bigheap();
    }
}

出力は次のようになります。

bs: Time = 8434
bh: Time = 7242
bs: Time = 1094
bh: Time = 2060
bs: Time = 842
bh: Time = 830
bs: Time = 785
bh: Time = 781
bs: Time = 782
bh: Time = 804
bs: Time = 782
bh: Time = 778
bs: Time = 792
bh: Time = 809
bs: Time = 785
bh: Time = 786
bs: Time = 782
bh: Time = 829
bs: Time = 786
bh: Time = 781

つまり、ヒープのスタックから割り当ててもまったく違いはありません。最初のわずかな「遅さ」は、「キャッシュのウォームアップ」に関係しています。

そして、あなたのコードが 2 つの間で異なる動作をする理由は別の理由であると私は確信していますsizeof buffer

于 2013-07-29T10:54:17.373 に答える
-1

からの戻り値を無視していますrecv。それは良いことではありません。部分的な読み取りは日常茶飯事であり、このような大きなバッファを渡す場合は、その可能性が非常に高くなります。有効なデータを含まないバッファの部分の処理を開始すると、予期しないことが起こる可能性があります。

最も一般的に使用されるプロトコルの最大フレーム サイズは 64kB です。システム内の何かがバッファー サイズの最下位 16 ビットのみを使用している可能性もあります (偶然にもゼロに設定されています)。これによりrecv、何もせずにすぐに返され、無限ループと高い CPU 使用率が発生します。

もちろん、これは動的に割り当てられたバッファーと何ら変わらないはずですが、ヒープユーザーコード使用sizeof (buffer)して、一度にポインターサイズのチャンクのみを読み取ることになった場合は、異なる可能性があります。

于 2013-07-30T00:28:20.050 に答える