【发布时间】:2017-06-29 08:58:55
【问题描述】:
我必须阅读一个包含文本的大文件,大约 3GB(和 4000 万行)。只是阅读它发生得非常快:
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
while ((line = br.readLine()) != null) {
//Nothing here
}
}
每次从上面的代码中读取line,我都会对字符串进行一些解析并进一步处理它。(一项艰巨的任务)。我尝试这样做多线程。
A)我试过BlockingQueue这样
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
String line;
BlockingQueue<String> queue = new ArrayBlockingQueue<>(100);
int numThreads = 5;
Consumer[] consumer = new Consumer[numThreads];
for (int i = 0; i < consumer.length; i++) {
consumer[i] = new Consumer(queue);
consumer[i].start();
}
while ((line = br.readLine()) != null) {
queue.put(line);
}
queue.put("exit");
} catch (FileNotFoundException ex) {
Logger.getLogger(ReadFileTest.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException | InterruptedException ex) {
Logger.getLogger(ReadFileTest.class.getName()).log(Level.SEVERE, null, ex);
}
class Consumer extends Thread {
private final BlockingQueue<String> queue;
Consumer(BlockingQueue q) {
queue = q;
}
public void run() {
while (true) {
try {
String result = queue.take();
if (result.equals("exit")) {
queue.put("exit");
break;
}
System.out.println(result);
} catch (InterruptedException ex) {
Logger.getLogger(ReadFileTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
这种方法比普通的单线程处理花费更多的时间。 我不知道为什么 - 我做错了什么?
B)我试过ExecutorService:
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
String line;
ExecutorService pool = Executors.newFixedThreadPool(10);
while ((line = br.readLine()) != null) {
pool.execute(getRunnable(line));
}
pool.shutdown();
} catch (FileNotFoundException ex) {
Logger.getLogger(ReadFileTest.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(ReadFileTest.class.getName()).log(Level.SEVERE, null, ex);
}
private static Runnable getRunnable(String run){
Runnable task = () -> {
System.out.println(run);
};
return task;
}
这种方法也比直接在 while 循环内打印需要更多时间。我做错了什么?
正确的做法是什么?
如何高效处理多线程读取line?
【问题讨论】:
-
这只是我的猜测:您的瓶颈是阅读本身,而不是处理。所以处理已经在不同线程上读取的行不会加速。快速搜索给了我这个结果:stackoverflow.com/questions/25711616/… 和接受的回复:stackoverflow.com/questions/9093888/…
-
您的第二个建议似乎很地道。我建议并行化更大的数据块而不是单行,例如,每个块 1 MB。
-
您的示例并不适合测试多线程。例如,在情况 A 中,您的所有线程都被“队列”阻塞,然后是系统 i/o。尝试一些真实的代码,可能会看到不同。
-
您说读取数据的解析将是一项“巨大的任务”。只需在您的消费者和每次读取原始单线程代码中的行之后添加一些等待时间,然后检查多线程版本的性能是否更好。
-
顺便说一句,使用
System.out.println()来测试多线程是一个非常糟糕的主意,因为它是同步的。因此,您的代码实际上将是单线程的,但会增加多线程的所有开销。
标签: java multithreading