3

私のプログラムでは、それぞれ 256 行で、1.txt から n.txt までのファイル名を持つ複数のテキスト ファイル (〜 800 ファイル以上) を読み取り、いくつかの処理ステップの後にデータベースに保存したいと考えています。私の問題は、データの読み取り速度です。読み取りループに OpenMP マルチスレッドを使用することで、プログラムを以前の約 2 倍まで高速化できました。もう少し速くする方法はありますか?私の実際のコードは

std::string CCD_Folder = CCDFolder; //CCDFolder is a pointer to a char array
int b = 0;
int PosCounter = 0;
int WAVENUMBER, WAVELUT;
std::vector<std::string> tempstr;
std::string inputline;
//Input
omp_set_num_threads(YValue);
#pragma omp parallel for private(WAVENUMBER) private(WAVELUT) private(PosCounter) private(tempstr) private(inputline)
    for(int i = 1; i < (CCD_Filenumbers+1); i++)
    {
        //std::cout << omp_get_thread_num() << ' ' << i << '\n';
        //Umwandlung und Erstellung des Dateinamens, Öffnen des Lesekanals
        std::string CCD_Filenumber = boost::lexical_cast<string>(i);
        std::string CCD_Filename = CCD_Folder + '\\' + CCD_Filenumber + ".txt";
        std::ifstream datain(CCD_Filename, std::ifstream::in);  
        while(!datain.eof())
        {
            std::getline(datain, inputline);
            //Processing

        };

    };

ここで定義されていないすべての変数は、私のコードの別の場所で定義されており、機能しています。では、このコードをもう少し高速化する可能性はありますか?
どうもありがとうございました!

4

4 に答える 4

8

いくつかの実験:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>

void generateFiles(int n) {
    char fileName[32];
    char fileStr[1032];

    for (int i=0;i<n;i++) {
        sprintf( fileName, "c:\\t\\%i.txt", i );
        FILE * f = fopen( fileName, "w" );
        for (int j=0;j<256;j++) {
            int lineLen = rand() % 1024;
            memset(fileStr, 'X', lineLen );
            fileStr[lineLen] = 0x0D;
            fileStr[lineLen+1] = 0x0A;
            fileStr[lineLen+2] = 0x00;
            fwrite( fileStr, 1, lineLen+2, f );         
        }
        fclose(f);
    }
}

void readFiles(int n) {
    char fileName[32];

    for (int i=0;i<n;i++) {
        sprintf( fileName, "c:\\t\\%i.txt", i );
        FILE * f = fopen( fileName, "r" );
        fseek(f, 0L, SEEK_END);
        int size = ftell(f);
        fseek(f, 0L, SEEK_SET);
        char * data = (char*)malloc(size);
        fread(data, size, 1, f);
        free(data);
        fclose(f);
    }   
}

DWORD WINAPI readInThread( LPVOID lpParam ) 
{ 
    int * number = (int *)lpParam;
    char fileName[32];

    sprintf( fileName, "c:\\t\\%i.txt", *number );
    FILE * f = fopen( fileName, "r" );
    fseek(f, 0L, SEEK_END);
    int size = ftell(f);
    fseek(f, 0L, SEEK_SET);
    char * data = (char*)malloc(size);
    fread(data, size, 1, f);
    free(data);
    fclose(f);

    return 0; 
} 


int main(int argc, char ** argv) {
    long t1 = GetTickCount();
    generateFiles(256);
    printf("Write: %li ms\n", GetTickCount() - t1 );

    t1 = GetTickCount();
    readFiles(256);
    printf("Read: %li ms\n", GetTickCount() - t1 );

    t1 = GetTickCount();

    const int MAX_THREADS = 256;

    int     pDataArray[MAX_THREADS];
    DWORD   dwThreadIdArray[MAX_THREADS];
    HANDLE  hThreadArray[MAX_THREADS]; 

    for( int i=0; i<MAX_THREADS; i++ )
    {

        pDataArray[i] = (int) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                sizeof(int));

        pDataArray[i] = i;

        hThreadArray[i] = CreateThread( 
            NULL,                   
            0,                      
            readInThread,       
            &pDataArray[i],          
            0,                      
            &dwThreadIdArray[i]);   
    } 

    WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, INFINITE);

    printf("Read (threaded): %li ms\n", GetTickCount() - t1 );

}

最初の関数は、テストデータセットを作成するための醜いものです(もっとうまくできることはわかっていますが、正直なところ時間がありません)

1 回目の実験 - シーケンシャル読み取り 2 回目の実験 - すべてを並行して読み取る

結果:

256 ファイル:

Write: 250 ms
Read: 140 ms
Read (threaded): 78 ms

1024 ファイル:

Write: 1250 ms
Read: 547 ms
Read (threaded): 843 ms

2 回目の試行は、長期的には「ダム」スレッドの作成が事態をさらに悪化させることを明確に示していると思います。もちろん、事前に割り当てられたワーカー、いくつかのスレッド プールなどの点で改善が必要ですが、ディスクから 100 ~ 200k を読み取るような高速な操作では、この機能をスレッドに移動するメリットはないと思います。もっと「賢い」ソリューションを書く時間はありませんが、ミューテックスなどのシステムコールを追加する必要があるため、はるかに高速になるとは思えません...

極端に行くと、メモリプールなどを事前に割り当てることを考えることができます..しかし、前に述べたように、コードが間違って投稿されました..それは数ミリ秒の問題ですが、確かに数秒ではありません

800 ファイル (1 行あたり 20 文字、256 行)

Write: 250 ms
Read: 63 ms
Read (threaded): 500 ms

結論:

答えは:

読み取りコードが間違っています。ファイルの読み取りが非常に遅いため、速度が大幅に向上し、タスクを並行して実行します。上記のコードでは、読み取りは実際にはスレッドを生成するための費用よりも高速です

于 2013-08-20T15:20:36.387 に答える
1

ディスクの読み取り制限に達している可能性があります。これは、オプションが多少制限されていることを意味します。これが常に発生する問題である場合は、別の RAID 構造を検討できます。これにより、複数の読み取りヘッドが同時にデータにアクセスできるため、読み取りスループットが向上します。

ディスク アクセスが本当にボトルネックになっているかどうかを確認するには、time コマンドを使用してプログラムを実行します。

>> /usr/bin/time -v <my program>

出力には、ディスクアクセスなどに必要な時間と比較して、使用していた CPU 時間が表示されます。

于 2013-08-20T14:48:22.267 に答える