2016-09-26 20 views
-3

Cで大きな.txtファイルを読み込もうとしています。私はfgets()でバージョンを作成しましたが、パフォーマンスはI/Oによって制限されています。だから、他の何かがfgets()よりもパフォーマンスが良くなる必要があり、mmap()がI/Oによって制限されないことがわかりました。だから私の質問は、mmap()とマルチスレッド(POSIXスレッド)でそれを行うことは可能ですか?Cでmmapのマルチスレッドでファイルを読み取る

Different threads to read(mmap() or something else) different parts of the file simultaneously

私はオンラインマルチスレッドでのmmap()に関するすべてのリソースを発見することができない、誰かがいくつかのサンプルコードで私を助けてと説明してくださいできます そして、ここでは何が必要でしょうか?マップファイルまたはデバイスmmapの説明は述べているメモリに

#include <sys/mman.h> 
void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off); 

-

のmmap:私はmmap状態のためのLinuxのマニュアルページには感謝

+1

異なるスレッドで同時にファイルの異なる部分を読み取る必要がありますか? – yano

+1

区切られたレコードを '\ n'読みたいですか?行がページ境界を超えている場合はどうなりますか? – wildplasser

+0

@yano Yesssあなたが言ったように、それを行う方法はありますか? – superrman777

答えて

0

、あなたの助けに非常に感謝されます:

mmap()は、仮想アドレスspaに新しいマッピングを作成します。呼び出し元プロセスのce。新しいマッピングの開始アドレスはaddrで指定されます。 length引数は、マッピングの長さを指定します。

次に、マニュアルページのコード例を示します。

#include <sys/mman.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#define handle_error(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0) 
int main(int argc, char *argv[]) 
{ 
    char *addr; 
    int fd; 
    struct stat sb; 
    off_t offset, pa_offset; 
    size_t length; 
    ssize_t s; 
    if (argc < 3 || argc > 4) { 
     fprintf(stderr, "%s file offset [length]\n", argv[0]); 
     exit(EXIT_FAILURE); 
    } 
    fd = open(argv[1], O_RDONLY); 
    if (fd == -1) 
     handle_error("open"); 
    if (fstat(fd, &sb) == -1)   /* To obtain file size */ 
     handle_error("fstat"); 
    offset = atoi(argv[2]); 
    pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1); 
     /* offset for mmap() must be page aligned */ 
    if (offset >= sb.st_size) { 
     fprintf(stderr, "offset is past end of file\n"); 
     exit(EXIT_FAILURE); 
    } 
    if (argc == 4) { 
     length = atoi(argv[3]); 
     if (offset + length > sb.st_size) 
      length = sb.st_size - offset; 
    } else { /* No length arg ==> display to end of file */ 
     length = sb.st_size - offset; 
    } 
    addr = mmap(NULL, length + offset - pa_offset, PROT_READ, 
       MAP_PRIVATE, fd, pa_offset); 
    if (addr == MAP_FAILED) 
     handle_error("mmap"); 
    s = write(STDOUT_FILENO, addr + offset - pa_offset, length); 
    if (s != length) { 
     if (s == -1) 
      handle_error("write"); 
     fprintf(stderr, "partial write"); 
     exit(EXIT_FAILURE); 
    } 
    exit(EXIT_SUCCESS); 
} 

これは私の仕事ですが、それはすべてLinuxのマニュアルページです。

+0

あなたの答えをありがとう、しかし私が必要とするのはマルチスレッドのmmapです – superrman777

1

あなたのアイデア自体は悪くありません。改行で区切られたファイルを仮定すると(つまり、問題なしに行間を切り取ることができます)、そのようなブロックを持つブロックを見つけることができます(別のプログラムから切り出したので、最初に確認してください)

// just in case 
#define _LARGEFILE_SOURCE 
#define _BSD_SOURCE 
#define _POSIX_C_SOURCE 200112L 

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 

// TODO: should be calculated 
#define FILE_PARTS 100 
// TODO: should not be global 
off_t positions[FILE_PARTS + 1]; 

int slice_file(FILE * fp) 
{ 
    off_t curr_pos = 0; 
    off_t filesize = 0; 
    off_t chunk_size = 0; 
    int fd; 
    int i, res; 
    char c; 

    struct stat sb; 

    // get size of file 
    fd = fileno(fp); 
    if (fd == -1) { 
    fprintf(stderr, "EBADF in prepare_and_backup() for data-file pointer\n"); 
    return 0; 
    } 

    if (fstat(fd, &sb) == -1) { 
    fprintf(stderr, "fstat() failed\n"); 
    return 0; 
    } 
    // check if it is a regular file 
    if ((sb.st_mode & S_IFMT) != S_IFREG) { 
    fprintf(stderr, "Not a regular file\n"); 
    return 0; 
    } 
    // TODO: check if filesize and chunksize >> 1 
    filesize = sb.st_size; 
    chunk_size = filesize/((off_t) FILE_PARTS); 

    positions[0] = 0; 
    curr_pos = 0; 

    for (i = 1; i < FILE_PARTS; i++) { 
    res = fseeko(fp, curr_pos, SEEK_SET); 
    if (res == -1) { 
     fprintf(stderr, "Error in fseeko(): %s\n", 
       strerror(errno)); 
     return 0; 
    } 
    curr_pos += chunk_size; 
    // look for the end of the line to cut at useful places 
    while ((c = fgetc(fp)) != EOF) { 
     curr_pos++; 
     // TODO: add code to honor Apple's special needs 
     if (c == '\n') { 
     c = fgetc(fp); 
     if (c == EOF) { 
      break; 
     } 
     curr_pos++; 
     break; 
     } 
    } 
    positions[i] = curr_pos - 1; 
    } 
    // Position of the end of the file 
    positions[i] = filesize; 
    // Is that even needed? 
    rewind(fp); 
    return 1; 
} 

スレッドを開始することができます。スレッドの開始点と終了点(上の関数で計算したものとそうでないものがあります)と、個々のスレッド内でのmマッピングを心配する必要はありません。出力がブロックと同じサイズであれば、インプレースで作業することもできます。あなたはNULLにそれを設定し、特定のアドレスのために気にしない場合は

EDIT

mmapの宣言は

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); 

です。
lengthは、マップを初期化するバイト数です。この場合、ファイル記述子fdの内容で埋められます。
この充填の開始点は、offsetによって1つの不快な警告が設定されています。ページサイズの倍数である必要があります(正確な数はsysconf(_SC_PAGE_SIZE)となります)。あまり問題ではなく、開始前にページに設定して、実際の開始時に作業を開始すれば、すべての必要な情報が存在します。あなたはそのページの残りの部分を無視することができます。

またはファイル全体を取り出してマップし、ドライブ上のファイルを使用するときと同じように使用します。すべてのスレッドにそのマップのブロック(必要な情報はpositions)を与え、そこから作業します。

最初のメリット:複数のCPUブロックを使用すると、OSによって簡単に移動できるため、複数のCPUでキャッシュミスが少なくなることもあります。すべてのCPU /グループに独自のRAMまたは少なくとも非常に大きなキャッシュがあるクラスタまたはその他のアーキテクチャを実行する場合は、これは必須です。

後者の利点:実装が簡単ですが、マップの大きな塊が1つあります。ランタイムに影響する場合もあります。

ヒント:近代的で高速なSSDでの私の経験:最近は読み込み速度が非常に速いため、マッピングの代わりに直接ファイルアクセスで簡単に始めることができます。かなり遅い「通常の」HDDであっても、合理的なスピードを得ることができます。上記のスニペットをリッピングしたプログラムは、120GB以上の大容量のCSVファイルを検索しなければならず、十分なRAMを搭載していないため、ドライブに十分なスペースがなくてDBにロードできませんでした。数年前)。それは鍵 - >「たくさんの、異なる、価値観」ファイルでしたが、ありがたいことに既にソートされていました。そこで私は、上記の方法(KEY-> position)でインデックスファイルを作成しましたが、私の例では100ブロックよりはるかに多くのブロックを作成しました。インデックスファイル内のキーもソートされていましたので、検索するキーが大きい場合(データは昇順でソートされています)、インデックスエントリよりキーがブロック内にあることを意味する場合は、位置が存在する場合はそれを示します。ブロックは、キャッシュとして動作するためにRAMの一部を保持するのに十分なほど小さかったが、あまり得られなかった。着信要求はかなり均一にランダムだった。

貧しい人のDBだからといって、ユーザーからの苦情なしに仕事をするのに十分速いです。

面白いことに、キーは英数字で、ソートアルゴリズムでは「aAbBcC ...」がソートされています。つまり、strcmpを直接使用することはできません。私はしばらくの間私の頭を傷つけましたが、解決策はかなり単純です:大文字小文字を無視して比較してください(例:strcasecmp、利用可能な場合)でない場合と等しい そうでなければ、通常の結果の逆を返しますstrncmp例えば、ちょうどreturn -strcmp(a,b);)。

あなたは仕事が必要な種類のデータについては非常に黙っていましたので、上記のことはあなたにはあまり関心がないかもしれません。

+0

申し訳ありません、mmapについての次のステップはmmapです(位置[i-> FILE_PARTS]、 chunk_size、PROT_READ、MAP_PRIVATE、fd、0)? – superrman777

関連する問題