我的电脑有8核,64G内存。我使用多线程的方式是否如下?它处理每个文档(filePath)中的一行并将结果存储到 Document 列表中,最后返回。
问题是,当设置“4”个线程时,我没有看到它运行得更快。我的测试数据所花费的时间始终与单线程运行所需的时间相同。我使用 Callable 的方式有什么问题吗?
List<Document> processDocs(String filePath) {
ExecutorService pool = Executors.newFixedThreadPool(4);
List<Document> processedDocs = new ArrayList<>();
try {
br = new BufferedReader(IOUtils.fileReader(filePath));
String line = null;
int docNo=0;
while ((line = br.readLine()) != null) {
line = line.trim();
Callable<Document> callable = new NLPTextThread(line, ++docNo);
Future<Document> future = pool.submit(callable);
try {
processedDocs.add(future.get());
} catch (InterruptedException e) {
log.error("InterruptedException " + line);
} catch (ExecutionException e) {
log.error("ExecutionException: " + line);
e.printStackTrace();
}
}
pool.shutdown();
return processedDocs;
}
编辑:关于“docNo”变量的线程安全性的另一个问题。我想将文档序列号传递给 Callable。在这种情况下,“docNo”变量是线程安全的吗?
最佳答案
事实上,您在提交可调用对象后立即调用 future.get()
,这使得您的代码有效地单线程为 get
block ,并且您没有提交在未来得到解决的同时,还有更多的任务要添加到池中。在一个循环中提交所有内容并存储 future。然后迭代 future 列表以收集结果。
这样更好:
List<Document> processDocs(String filePath) {
List<Callable<Document>> tasks = new ArrayList<>();
try {
BufferedReader br = new BufferedReader(IOUtils.fileReader(filePath));
String line = null;
while ((line = br.readLine()) != null) {
tasks.add(new NLPTextThread(line.trim());
}
ExecutorService executor = Executors.newfixedThreadPool(4);
return executor.invokeAll(tasks)
.stream()
.map(future -> {
try {
return future.get();
} catch (Exception e) {
throw new IllegalStateException(e);
}
}).collect(Collectors.toList());
}
PS.
我想我也会强调 commeters 在原始问题上提出的 IO 问题。
如果您的每行文件的 NLPTextThread
执行时间可以忽略不计(与从文件中读取此行所需的时间相比),我认为您不会看到显着 使用线程池改进运行时间,因为在这种情况下,当您在主线程(单线程)上读取单个大文件时,IO 实际上是一个瓶颈。如果您将输入(如果很大)分成多个文件并并行处理每个文件,您可能会看到更高的性能提升。只是一些值得深思的东西。
关于java - 我的多线程代码运行速度并不快,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44733366/