2011-08-26 19 views
6

可能な限り速く1バイトのファイルをファイルからD2アプリケーションに読み込みたい。アプリケーションは1バイトあたりバイトを必要とするため、データの大きなブロックを読み取ることは、リーダーへのインタフェースのオプションではありません。D2のバイトを読み込む最速の方法

このため、私はC++、Java、D2で簡単な実装を作成しました:https://github.com/gizmomogwai/performance

私が見てきたように、アプリケーションコードとメモリマップされたファイルでプレーンリード、バッファを試しました。 私の用途では、メモリマップされたソリューションがうまく機能しましたが、奇妙なことはD2がjavaよりも遅いということです。私はD2がC++とJava(C++コードは-O3 -gでコンパイルされ、D2コードは-O-releaseでコンパイルされている)の間に置くことを望んでいました。

ここで私が間違っていることと、D2実装をスピードアップする方法を教えてください。あなたがここにユースケースのアイデアを与えることを

は、C++の実装です:

class StdioFileReader { 
private: 
    FILE* fFile; 
    static const size_t BUFFER_SIZE = 1024; 
    unsigned char fBuffer[BUFFER_SIZE]; 
    unsigned char* fBufferPtr; 
    unsigned char* fBufferEnd; 

public: 
    StdioFileReader(std::string s) : fFile(fopen(s.c_str(), "rb")), fBufferPtr(fBuffer), fBufferEnd(fBuffer) { 
    assert(fFile); 
    } 
    ~StdioFileReader() { 
    fclose(fFile); 
    } 

    int read() { 
    bool finished = fBufferPtr == fBufferEnd; 
    if (finished) { 
     finished = fillBuffer(); 
     if (finished) { 
    return -1; 
     } 
    } 
    return *fBufferPtr++; 
    } 

private: 
    bool fillBuffer() { 
    size_t l = fread(fBuffer, 1, BUFFER_SIZE, fFile); 
    fBufferPtr = fBuffer; 
    fBufferEnd = fBufferPtr+l; 
    return l == 0; 
    } 
}; 

size_t readBytes() { 
    size_t res = 0; 
    for (int i=0; i<10; i++) { 
    StdioFileReader r("/tmp/shop_with_ids.pb"); 
    int read = r.read(); 
    while (read != -1) { 
     ++res; 
     read = r.read(); 
    } 
    } 
    return res; 
} 

Dで「同じ」ソリューションに比べてはるかに高速である:

struct FileReader { 

    private FILE* fFile; 
    private static const BUFFER_SIZE = 8192; 
    private ubyte fBuffer[BUFFER_SIZE]; 
    private ubyte* fBufferPtr; 
    private ubyte* fBufferEnd; 

    public this(string fn) { 
    fFile = std.c.stdio.fopen("/tmp/shop_with_ids.pb", "rb"); 
    fBufferPtr = fBuffer.ptr; 
    fBufferEnd = fBuffer.ptr; 
    } 
    public int read(ubyte* targetBuffer) { 
    auto finished = fBufferPtr == fBufferEnd; 
    if (finished) { 
     finished = fillBuffer(); 
     if (finished) { 
     return 0; 
     } 
    } 
    *targetBuffer = *fBufferPtr++; 
    return 1; 
    } 
    private bool fillBuffer() { 
    fBufferPtr = fBuffer.ptr; 
    auto l = std.c.stdio.fread(fBufferPtr, 1, BUFFER_SIZE, fFile); 
    fBufferEnd = fBufferPtr + l; 
    return l == 0; 
    } 
} 

size_t readBytes() { 
    size_t count = 0; 
    for (int i=0; i<10; i++) { 
    auto reader = FileReader("/tmp/shop_with_ids.pb"); 
    ubyte buffer[1]; 
    ubyte* p = buffer.ptr; 
    auto c = reader.read(p); 
    while (1 == c) { 
     ++count; 
     c = reader.read(p); 
    } 
    } 
    return count; 
} 
+1

私はDとJavaで他の関連しないコーディングを行っています(数学的な計算が多い)。そして、Javaはテストで少し速くなっていることが分かりました。私は、あなたが今日Javaをそれほど遅くすることを期待すべきではないと思います.JITコンパイラは最適化に非常に優れています。 –

+1

ええ...あなたは正しい...私はJavaがcppよりもはるかに遅いとは思っていませんが(それはまだデフォルトのjitを使った私のデモの例です)、しかし私のポイントはdがさらに遅いということです。私はdがcppと同等であることを望んだ。 – Gizmomogwai

+0

はい、数ヶ月前にJavaアルゴリズムをDに変換したときもそうでした。私は、彼らはコード最適化を修正するいくつかの癖があると思います。またはGCがちょうど本当に悪いですし、遅いので、それを回してみてください? –

答えて

3

それは非常に可能性がありますsfreadのため。 CのようにDで同じことをすることは誰も保証しません - あなたはDigital Mars C++コンパイラを使用していない限り、別のCRTを使用する可能性が非常に高いです。

これは、ライブラリが同期などの処理を遅らせるようなことをしている可能性があることを意味します。あなたが知る唯一の方法は、force Dに、リンカに同じライブラリにリンクするように指示して、Cと同じライブラリを使用させることです。

あなたがそうするまで、あなたはリンゴとオレンジを比較しています。それが不可能な場合は、からOSを直接に電話してください。の結果を比較すると、両方の呼び出しが同じであることが保証されます。あなたがstd.stdio moduleを使用した場合に何が起こるか

+0

あなたはまったく正しいです。私はfreadの実装が似ているかどうかわからない。しかし、私の質問は、javaやC++のような速さでd2の機能を実装する方法です。 – Gizmomogwai

+0

@ギズモモワイ:そうですが、この質問の意味は、Dは本質的に遅いということです。基本的に多くのオーバーヘッドが必要となるため、また、1つの小さな領域がうまく最適化されていないために遅い言語であるため、本質的に遅い言語には大きな違いがあります。 – dsimcha

+0

@Gizmomogwai:JavaやC++のように高速に実装するには、何をしていてもかまいません。つまり、ネイティブOS呼び出しを使用して独自のバッファ付きラッパーを作成する必要があります( 'ReadFile' on Windows)、それを使って、それがどうなるかを見てください。それは言語問題か図書館の問題かを教えてくれるでしょう。 – Mehrdad

1

import std.stdio; 

struct FileReader { 

    private File fFile; 
    private enum BUFFER_SIZE = 8192;//why not enum? 
    private ubyte[BUFFER_SIZE] fBuffer=void;//avoid (costly) initialization to 0 
    private ubyte[] buff; 

    public this(string fn) { 
    fFile = File("/tmp/shop_with_ids.pb", "rb"); 
    } 

    /+ 
    public ~this(){//you really should have been doing this if you used std.c.stdio.fopen 
       //but it's unnecessary for std.stdio's File (it's ref counted) 
    fFile.close(); 
    } 
    +/ 

    public int read(out ubyte targetBuffer) { 
    auto finished = buff.length==0; 
    if (finished) { 
     finished = fillBuffer(); 
     if (finished) { 
     return 0; 
     } 
    } 
    targetBuffer = buff[0]; 
    buff = buff[1..$]; 
    return 1; 
    } 
    private bool fillBuffer() { 
    if(!fFile.isOpen())return false; 

    buff = fFile.rawRead(fBuffer[]); 

    return buff.length>0; 
    } 
} 

size_t readBytes() { 
    size_t count = 0; 
    for (int i=0; i<10; i++) { 
    auto reader = FileReader("/tmp/shop_with_ids.pb"); 
    ubyte buffer; 
    auto c = reader.read(buffer); 
    while (1 == c) { 
     ++count; 
     c = reader.read(buffer); 
    } 
    } 
    return count; 
} 

あなたは真の速度比較をしたい場合は、-release -O -inlineでコンパイルする必要があります(これは、デバッグ(主に配列OOBチェックをオフに)何を最適化し、インライン

+0

あなたのコメントに感謝します。実際に私は-O-releaseでd2コードをコンパイルしました(私のすべての例で-inlineが遅かった)。私はあなたのプログラムを修正しました(fillBufferはbuff.length == 0を返します)、私のベンチマークは私のマシンで600msでした(これはcpp-mmappedソリューションである80msと比較して)。 githubページの表を参照してください。 – Gizmomogwai

関連する問題