2011-08-26 23 views
6

我想尽可能快地将单个字节从文件读取到D2应用程序中。应用程序需要每个字节的字节,因此读取较大的数据块不是读取器接口的选项。在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中做同样的事情 - 你很可能完全使用不同的CRT(除非你使用的是Digital Mars C++编译器?)。

这意味着图书馆可能会做一些事情,比如同步等,这会降低速度。通过告诉链接器链接到相同的库,您可以知道的唯一方法是通过强制 D使用与C相同的库。

直到你可以做到这一点,你正在比较苹果和橘子。如果这是不可能的,然后直接从调用操作系统然后比较结果 - 这样你就可以保证底层调用是相同的两个。

+0

你是完全正确的。我不知道fread的实现是否相似。但我的问题是如何在d2中像在java甚至C++中一样快地实现功能。 – Gizmomogwai

+0

@ Gizmomogwai:对,但这个问题的含义是D本质上很慢。语言本质上很慢,因为它的设计从根本上需要大量开销,而语言中一个小区域由于尚未进行优化而很慢,所以语言之间存在很大差异。 – dsimcha

+0

@Gizmomogwai:为了在Java中或在C++中实现它,你只需要做他们正在做的任何事情 - 这可能意味着你应该在本地OS调用('ReadFile')上创建自己的缓冲包装器Windows)并使用它,然后看看它是如何发展的。这会告诉你这是语言问题还是图书馆问题。 – Mehrdad

1

如果使用std.stdio module会发生什么:

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检查)

优化和内联什么它可以)(当然也与C++解决方案类似)

+0

感谢您的意见。实际上我用-O编译了d2代码 - 释放(在我的所有示例中,内嵌比较慢)。我更正了你的程序(fillBuffer应该返回buff.length == 0),我的基准测试在我的机器上测试了600ms(与80ms相比,这是cpp-mmapped解决方案)。请参阅github页面上的表格。 – Gizmomogwai

相关问题