Самый быстрый способ обработки Java IO с использованием ASCII-строк - PullRequest
1 голос
/ 21 января 2010

Я работаю с потоком ввода / вывода ASCII через сокет, и скорость критична. Я слышал, что использование правильной техники Java действительно имеет значение. У меня есть учебник, в котором говорится, что использование буферов - лучший способ, но также предлагается создание цепочки с DataInputStreamReader.

Для вывода я использую BufferedOutputStream с OutputStreamWriter, который, кажется, в порядке. Но я не уверен, что использовать для входного потока. Я работаю над новыми линиями, так что будет ли полезен Сканер? Скорость имеет решающее значение, мне нужно как можно быстрее вывести данные из сети.

Спасибо.

PH

Ответы [ 4 ]

3 голосов
/ 22 января 2010

Только для смеха ...

socket = new ServerSocket(2004, 10);
connection = socket.accept();
in = connection.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
String line = null;
do {
    line = br.readLine();
} while (!"done".equals(line));

С LOOPBACK, т. Е. Просто выполняется на localhost с локальными процессами, на моей машине и с подходящим "глупым" клиентом.

requestSocket = new Socket("localhost", 2004);
out = requestSocket.getOutputStream();
PrintWriter pw = new PrintWriter(out);
String line =  "...1000 characters long..."; 
for (int i = 0; i < 2000000 - 1; i++) {
    pw.println(line);
}
line = "done";
pw.println(line);
pw.flush();

Вы заметите, что это посылает 2M строк "1000 символов". Это просто грубый тест производительности.

На моей машине с обратной связью скорость передачи составляет ~ 190 МБ / с. Байты, а не биты. 190 000 строк / сек.

Моя точка зрения заключается в том, что «простой» способ использования Java-сокетов для костей довольно быстр. Это насытит любое обычное сетевое соединение (то есть сеть будет замедлять вас больше, чем ваш ввод-вывод).

Вероятно, "достаточно быстро".

Какой трафик вы ожидаете?

1 голос
/ 21 января 2010

Если скорость абсолютно критична, рассмотрите возможность использования NIO. Вот пример кода, выложенный для того же вопроса.

http://lists.apple.com/archives/java-dev/2004/Apr/msg00051.html

РЕДАКТИРОВАТЬ: Вот еще один пример

http://www.java2s.com/Code/Java/File-Input-Output/UseNIOtoreadatextfile.htm

РЕДАКТИРОВАТЬ 2: Я написал этот микробенчмарк, чтобы вы начали измерять производительность различных подходов. Некоторые люди отмечают, что NIO не будет работать быстрее, потому что вам нужно будет больше работать, чтобы «преобразовать» данные в пригодную для использования форму, чтобы вы могли проверить это на основе того, что вы пытаетесь сделать. Когда я запускал этот код на своем компьютере, код NIO был примерно в 3 раза быстрее с файлом размером 45 мегабайт и в 5 раз быстрее с файлом размером 100 мегабайт.

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Scanner;

public class TestStuff {

    public static void main(final String[] args)
            throws IOException, InterruptedException {

        final String file_path = "c:\\test-nio.txt";
        readFileUsingNIO(file_path);
        readFileUsingScanner(file_path);

    }

    private static void readFileUsingScanner(final String path_to_file)
            throws FileNotFoundException {
        Scanner s = null;

        final StringBuilder builder = new StringBuilder();
        try {
            System.out.println("Starting to read the file using SCANNER");
            final long start_time = System.currentTimeMillis();
            s = new Scanner(new BufferedReader(new FileReader(path_to_file)));
            while (s.hasNext()) {
                builder.append(s.next());
            }
            System.out.println("Finished!  Read took " + (System.currentTimeMillis() - start_time) + " ms");
        }
        finally {
            if (s != null) {
                s.close();
            }
        }

    }

    private static void readFileUsingNIO(final String path_to_file)
            throws IOException {
        FileInputStream fIn = null;
        FileChannel fChan = null;
        long fSize;
        ByteBuffer mBuf;

        final StringBuilder builder = new StringBuilder();
        try {
            System.out.println("Starting to read the file using NIO");
            final long start_time = System.currentTimeMillis();
            fIn = new FileInputStream("c:\\test-nio.txt");
            fChan = fIn.getChannel();
            fSize = fChan.size();
            mBuf = ByteBuffer.allocate((int) fSize);
            fChan.read(mBuf);
            mBuf.rewind();
            for (int i = 0; i < fSize; i++) {
                //System.out.print((char) mBuf.get());
                builder.append((char) mBuf.get());
            }
            fChan.close();
            fIn.close();
            System.out.println("Finished!  Read took " + (System.currentTimeMillis() - start_time) + " ms");
        }
        catch (final IOException exc) {
            System.out.println(exc);
            System.exit(1);
        }
        finally {
            if (fChan != null) {
                fChan.close();
            }
            if (fIn != null) {
                fIn.close();
            }
        }

    }
0 голосов
/ 21 января 2010

Я бы сделал что-нибудь с BufferedReader в соответствии с:

Collection<String> lines = new ArrayList<String>();
BufferedReader reader = new BufferedReader( new InputStreamReader( Foo.getInputStream()));
while(reader.ready())
{
    lines.add( reader.readLine());
}

myClass.processData(lines); //Process the data after it is off the network.

В зависимости от вашей ситуации у вас может быть дополнительный поток, который обрабатывает элементы в «строках» по мере его заполнения, но тогда вам нужно будет использовать другую структуру для поддержки коллекции - такую, которая может использоваться одновременно .

0 голосов
/ 21 января 2010

A Scanner используется для текста с разделителями. Вы не говорили о том, как выглядят ваши данные, поэтому я не могу это комментировать.

Если вы просто хотите читать до каждого символа новой строки, используйте

BufferedReader r = new BufferedReader(new InputStreamReader(Socket.getInputStream()))

и

r.readLine()

Когда вы получите нулевое значение, вы узнаете, что исчерпали данные в потоке.

Что касается скорости, они оба просто читают данные из потока. Поэтому, предполагая, что вам не нужна дополнительная функциональность Scanner, я не вижу особой причины использовать ее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...