Java:对InputStream的并发读取

时间:2013-04-23 01:01:25

标签: java performance concurrency inputstream

现在一直在四处寻找,我对这个问题感到有些困惑。我希望能够获取输入流并在段中同时读取它。这些段不会相互交互,它们只是要在上载文件的数据库中插入或更新的值。是否可以通过设置段大小来同时读取输入流,然后在旋转新线程以处理转换和插入/更新之前只是向前跳过?

本质上,文件是ID的列表(每行一个ID),但如果我可以指定分隔符则更好。有些文件可能很大,所以我想处理并将数据转换成段,以便在插入/更新到数据库之后可以释放JVM内存。这可能吗?如果有的话,那里有任何图书馆已经这样做了吗?

提前干杯,谢谢,

阿列克谢蓝。

3 个答案:

答案 0 :(得分:7)

一个好的方法可能是让一个读取器读取块然后将每个块从一个线程池交给一个工作线程。鉴于这些将被插入到数据库中,与读取输入相比,插入将是缓慢的部分,因此单个线程应该足以进行读取。

下面是一个示例,它将每行的处理从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));
        }
    }
}

答案 1 :(得分:2)

首先,要从不同的偏移量开始同时读取文件,您需要随机访问到文件,这意味着从任何位置读取文件。 Java允许在java.in中使用RandomAccessFile或在java.nio中使用SeekableByteChannel:

Best Way to Write Bytes in the Middle of a File in Java

http://docs.oracle.com/javase/tutorial/essential/io/rafs.html

我认为出于速度原因你更喜欢java.nio。 Java NIO FileChannel versus FileOutputstream performance / usefulness

现在您知道如何从任何位置读取,但您需要同时执行此操作。使用相同的文件访问对象是不可能的,因为它们保存文件中的位置。因此,您需要与线程一样多的文件访问对象。因为你正在阅读不写作应该是好的。

现在您知道如何从许多不同的偏移量同时读取同一文件。

但考虑一下表现。尽管线程数量只有一个磁盘驱动器和随机读取(许多线程访问同一个文件),但性能比顺序读取要快得多(一个线程读取一个文件)。即使它突袭0或1 - 也无所谓。顺序读取总是快得多。所以在你的情况下,我会建议你在一个线程中读取文件,并为其他线程提供来自该读取线程的数据。

答案 2 :(得分:1)

我认为你不能同时读取InputStream。这就是合同定义读取,重置和标记的原因 - 这个想法是流在内部跟踪已读取的内容和未读取的内容。

如果您正在阅读文件,只需打开多个流即可。您可以使用skip()方法向前移动其他线程的标记,以避免重复的线处理。 BufferedReader也可能有所帮助,因为它提供了阅读line by line