Java: параллельные чтения на InputStream
уже некоторое время оглядываюсь, и я немного запутался в этом вопросе. Я хочу иметь возможность принимать входной поток и читать его одновременно в сегментах. Сегменты не взаимодействуют друг с другом, это просто значения, которые нужно вставить или обновить в базе данных из загруженного файла. Можно ли одновременно считывать входной поток, задав размер сегмента, а затем просто пропускать вперед, прежде чем закручивать новый поток для обработки преобразования и вставить / обновить?
по существу файл представляет собой список идентификаторов (один идентификатор на строку), хотя было бы предпочтительнее, если бы я мог указать разделитель. Некоторые файлы могут быть огромными, поэтому я хотел бы обработать и преобразовать данные в сегменты, чтобы после вставки / обновления в базу данных Память JVM могла быть освобождена. Возможно ли это? И если да, то есть ли библиотеки, которые уже это делают?
ура и спасибо заранее,
Алексей Голубых.
3 ответов
вместо этого хороший подход может заключаться в том, чтобы иметь одного читателя, который читает куски, а затем передает каждый кусок рабочему потоку из пула потоков. Учитывая, что они будут вставлены в базу данных, вставки будут медленными частями по сравнению с чтением ввода, поэтому одного потока должно быть достаточно для чтения.
Ниже приведен пример, который передает обработку каждой строки из System.in
рабочий поток. Производительность вставок базы данных намного лучше, если вы выполняете большое количество вставок в одной транзакции, поэтому передача в группе, скажем, 1000 строк, будет лучше, чем передача в одной строке, как в Примере.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static class Worker implements Runnable {
private final String line;
public Worker(String line) {
this.line = line;
}
@Override
public void run() {
// Process line here.
System.out.println("Processing line: " + line);
}
}
public static void main(String[] args) throws IOException {
// Create worker thread pool.
ExecutorService service = Executors.newFixedThreadPool(4);
BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
String line;
// Read each line and hand it off to a worker thread for processing.
while ((line = buffer.readLine()) != null) {
service.execute(new Worker(line));
}
}
}
прежде всего, чтобы читать файл одновременно, начиная с разных смещений, вам нужно произвольный доступ для файла это означает чтение файла из любой позиции. Java позволяет с позиции в Java.В или с SeekableByteChannel в Java.НИО:
лучший способ записи байтов в середине файла в Java
http://docs.oracle.com/javase/tutorial/essential/io/rafs.html
Я думаю, для скорости причины, по которым вы предпочтете java.НИО. Java NIO FileChannel против fileoutputstream производительность / полезность
теперь вы знаете, как читать из любой позиции, но вам нужно сделать это одновременно. Это невозможно с тем же объектом доступа к файлу, потому что они занимают позицию в файле. Таким образом, вам нужно столько объектов доступа к файлам, сколько потоков. Поскольку вы читаете, а не пишете, это должно быть нормально.
теперь вы знаете, как читать один и тот же файл одновременно много разных смещений.
но подумайте о производительности. Несмотря на количество потоков, у вас есть только один диск и случайные чтения (многие потоки обращаются к одному и тому же файлу) производительность намного медленнее, чем последовательные чтения (один поток читает один файл). Даже если это raid 0 или 1 - не имеет значения. Последовательное чтение всегда происходит намного быстрее. Поэтому в вашем случае я бы посоветовал вам прочитать файл в одном потоке и предоставить другим потокам данные из этого потока чтения.
Я не думаю, что вы можете читать InputStream одновременно. Вот почему контракт определяет чтение, сброс и отметку-идея заключается в том, что поток отслеживает внутренне, что было прочитано, а что нет.
Если Вы читаете файл, просто откройте несколько потоков. Вы можете использовать пропустить() метод для перемещения маркера вперед для других потоков, чтобы избежать обработки повторяющихся строк. командой bufferedreader может помочь некоторым тоже, так как он предлагает чтение линия по линия.