28

以下でCharBufferaより a を好む理由はありますか?char[]

CharBuffer buf = CharBuffer.allocate(DEFAULT_BUFFER_SIZE);
while( in.read(buf) >= 0 ) {
  out.append( buf.flip() );
  buf.clear();
}

対。

char[] buf = new char[DEFAULT_BUFFER_SIZE];
int n;
while( (n = in.read(buf)) >= 0 ) {
  out.write( buf, 0, n );
}

( inaReaderoutaはどこにありWriterますか)?

4

7 に答える 7

18

CharBufferいいえ、この場合a を好む理由は本当にありません。

ただし、一般に、CharBuffer(およびByteBuffer) は API を単純化し、正しい処理を促進することができます。パブリック API を設計している場合は、バッファー指向の API を検討する価値があります。

于 2008-11-16T22:09:49.780 に答える
7

この比較をミニベンチマークしたいと思いました。

以下は私が書いたクラスです。

問題は、CharBuffer のパフォーマンスがそれほど悪いとは信じられないということです。私は何を間違えたのですか?

編集: 以下の 11 番目のコメント以降、コードと出力時間を編集しました。パフォーマンスは全体的に向上していますが、それでも時間に大きな違いがあります。コメントに記載されている out2.append((CharBuffer)buff.flip()) オプションも試しましたが、以下のコードで使用されている書き込みオプションよりもはるかに遅かったです。

結果: (ミリ秒単位の時間)
char[] : 3411
CharBuffer: 5653

public class CharBufferScratchBox
{
    public static void main(String[] args) throws Exception
    {
        // Some Setup Stuff
        String smallString =
                "1111111111222222222233333333334444444444555555555566666666667777777777888888888899999999990000000000";

        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < 1000; i++)
        {
            stringBuilder.append(smallString);
        }
        String string = stringBuilder.toString();
        int DEFAULT_BUFFER_SIZE = 1000;
        int ITTERATIONS = 10000;

        // char[]
        StringReader in1 = null;
        StringWriter out1 = null;
        Date start = new Date();
        for (int i = 0; i < ITTERATIONS; i++)
        {
            in1 = new StringReader(string);
            out1 = new StringWriter(string.length());

            char[] buf = new char[DEFAULT_BUFFER_SIZE];
            int n;
            while ((n = in1.read(buf)) >= 0)
            {
                out1.write(
                        buf,
                        0,
                        n);
            }
        }
        Date done = new Date();
        System.out.println("char[]    : " + (done.getTime() - start.getTime()));

        // CharBuffer
        StringReader in2 = null;
        StringWriter out2 = null;
        start = new Date();
        CharBuffer buff = CharBuffer.allocate(DEFAULT_BUFFER_SIZE);
        for (int i = 0; i < ITTERATIONS; i++)
        {
            in2 = new StringReader(string);
            out2 = new StringWriter(string.length());
            int n;
            while ((n = in2.read(buff)) >= 0)
            {
                out2.write(
                        buff.array(),
                        0,
                        n);
                buff.clear();
            }
        }
        done = new Date();
        System.out.println("CharBuffer: " + (done.getTime() - start.getTime()));
    }
}
于 2008-11-17T09:42:28.897 に答える
4

実際には、違いは実際には10%未満であり、他の人が報告している30%ではありません。

5MBのファイルを24回読み書きするために、私の番号はプロファイラーを使用して取得しました。彼らは平均していた:

char[] = 4139 ms
CharBuffer = 4466 ms
ByteBuffer = 938 (direct) ms

個々のテストは、CharBufferを数回支持しました。

また、ファイルベースのIOをインメモリIOに置き換えてみましたが、パフォーマンスは同様でした。あるネイティブストリームから別のネイティブストリームに転送しようとしている場合は、「直接」のByteBufferを使用することをお勧めします。

パフォーマンスの差が10%未満であるため、実際には、CharBufferを使用します。構文がより明確になり、無関係な変数が少なくなり、より直接的な操作(つまり、CharSequenceを要求するもの)を実行できます。

ベンチマークは以下のとおりです...BufferedReaderが外部ではなくテストメソッドの内部に割り当てられているため、少し間違っています...ただし、以下の例では、IO時間を分離し、内部のサイズを変更する文字列やバイトストリームなどの要因を排除できます。メモリバッファなど。

public static void main(String[] args) throws Exception {
    File f = getBytes(5000000);
    System.out.println(f.getAbsolutePath());
    try {
        System.gc();
        List<Main> impls = new java.util.ArrayList<Main>();
        impls.add(new CharArrayImpl());
        //impls.add(new CharArrayNoBuffImpl());
        impls.add(new CharBufferImpl());
        //impls.add(new CharBufferNoBuffImpl());
        impls.add(new ByteBufferDirectImpl());
        //impls.add(new CharBufferDirectImpl());
        for (int i = 0; i < 25; i++) {
            for (Main impl : impls) {
                test(f, impl);
            }
            System.out.println("-----");
            if(i==0)
                continue; //reset profiler
        }
        System.gc();
        System.out.println("Finished");
        return;
    } finally {
        f.delete();
    }
}
static int BUFFER_SIZE = 1000;

static File getBytes(int size) throws IOException {
    File f = File.createTempFile("input", ".txt");
    FileWriter writer = new FileWriter(f);
    Random r = new Random();
    for (int i = 0; i < size; i++) {
        writer.write(Integer.toString(5));
    }
    writer.close();
    return f;
}

static void test(File f, Main impl) throws IOException {
    InputStream in = new FileInputStream(f);
    File fout = File.createTempFile("output", ".txt");
    try {
        OutputStream out = new FileOutputStream(fout, false);
        try {
            long start = System.currentTimeMillis();
            impl.runTest(in, out);
            long end = System.currentTimeMillis();
            System.out.println(impl.getClass().getName() + " = " + (end - start) + "ms");
        } finally {
            out.close();
        }
    } finally {
        fout.delete();
        in.close();
    }
}

public abstract void runTest(InputStream ins, OutputStream outs) throws IOException;

public static class CharArrayImpl extends Main {

    char[] buff = new char[BUFFER_SIZE];

    public void runTest(InputStream ins, OutputStream outs) throws IOException {
        Reader in = new BufferedReader(new InputStreamReader(ins));
        Writer out = new BufferedWriter(new OutputStreamWriter(outs));
        int n;
        while ((n = in.read(buff)) >= 0) {
            out.write(buff, 0, n);
        }
    }
}

public static class CharBufferImpl extends Main {

    CharBuffer buff = CharBuffer.allocate(BUFFER_SIZE);

    public void runTest(InputStream ins, OutputStream outs) throws IOException {
        Reader in = new BufferedReader(new InputStreamReader(ins));
        Writer out = new BufferedWriter(new OutputStreamWriter(outs));
        int n;
        while ((n = in.read(buff)) >= 0) {
            buff.flip();
            out.append(buff);
            buff.clear();
        }
    }
}

public static class ByteBufferDirectImpl extends Main {

    ByteBuffer buff = ByteBuffer.allocateDirect(BUFFER_SIZE * 2);

    public void runTest(InputStream ins, OutputStream outs) throws IOException {
        ReadableByteChannel in = Channels.newChannel(ins);
        WritableByteChannel out = Channels.newChannel(outs);
        int n;
        while ((n = in.read(buff)) >= 0) {
            buff.flip();
            out.write(buff);
            buff.clear();
        }
    }
}
于 2008-11-20T01:19:34.357 に答える
4

これがバッファで行っている唯一のことである場合、このインスタンスではおそらく配列の方が適切な選択です。

CharBuffer には余分なクロムがたくさんありますが、この場合はどれも関係がなく、速度がわずかに低下するだけです。

より複雑にする必要がある場合は、後でいつでもリファクタリングできます。

于 2008-11-16T21:16:17.250 に答える
2

I think that CharBuffer and ByteBuffer (as well as any other xBuffer) were meant for reusability so you can buf.clear() them instead of going through reallocation every time

If you don't reuse them, you're not using their full potential and it will add extra overhead. However if you're planning on scaling this function this might be a good idea to keep them there

于 2008-11-17T01:56:17.823 に答える
1

You should avoid CharBuffer in recent Java versions, there is a bug in #subsequence(). You cannot get a subsequence from the second half of the buffer since the implementation confuses capacity and remaining. I observed the bug in java 6-0-11 and 6-0-12.

于 2009-02-12T09:50:45.923 に答える
1

CharBuffer バージョンは少し複雑ではなく (変数が 1 つ少ない)、バッファー サイズの処理がカプセル化され、標準 API が使用されます。通常、私はこれを好みます。

ただし、少なくとも場合によっては、配列バージョンを優先する正当な理由が 1 つあります。CharBuffer は Java 1.4 でのみ導入されたため、以前のバージョンにデプロイする場合は、 Charbuffer を使用できません(自分でロールバックポートを使用しない限り)。

PS バックポートを使用している場合は、バックポートされたコードの「実際の」バージョンを含むバージョンに追いついたら、忘れずに削除してください。

于 2008-11-17T01:43:07.150 に答える