2010-01-21 4 views
1

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

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

Спасибо.

РН

+0

BufferedReader иногда LOTS медленнее, чем ручная буферизация. Вам необходимо ПРОФИЛЬ различных решений для вашего конкретного случая и посмотреть, какой из них самый быстрый. BufferedReader не всегда самый быстрый. –

ответ

0

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

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

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

и

r.readLine()

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

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

-1

Я хотел бы сделать что-то с 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

с использованием Vector НЕПРАВИЛЬНО для производительности, он синхронизирован. Вместо этого используйте Список . Также предполагается, что весь набор входных данных будет находиться в памяти. Лучшим способом было бы обрабатывать каждую строку по мере ее чтения. –

+0

Изменил его в ArrayList, который несинхронизирован. –

1

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

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

EDIT: Вот еще один пример

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

EDIT 2: Я написал эту microbenchmark, чтобы вы начали на измерении производительности различных подходов. Некоторые люди прокомментировали, что 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(); 
      } 
     } 

    } 
+1

В моем учебнике говорится, что я буду получать повышение производительности, если вы используете много потоков для разных входов. У меня только один вход, но идея заставляет меня точно. –

+0

Ваша книга неверна, если вы выполняете нетривиальную обработку входных строк. –

+0

nio имеет решающее значение для + масштабируемости +, _not_ speed. nio может быть медленнее для выделенного потока. – james

3

Просто для смеха ...

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, т.е. просто работает на локальный с локальными процессами, на моей машине, и с подходящим «тупым» клиентом.

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 символов». Это просто сырой тест пропускной способности.

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

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

Вероятно «достаточно быстро».

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

+0

Быстро, но медленнее, чем 'Google Fiber': D, хороший чувак. – 2014-07-02 12:04:01