我希望用Java读取文件的内容。我有大约8000个文件来读取内容并将其放在HashMap中(路径,内容)。我认为使用Threads可以选择这样做来加快这个过程。 据我所知,所有8000个文件都在不同的线程中读取它们的内容是不可能的(我们可能想限制线程),对它有何评论?另外我是Java新手中的新手,有没有人可以帮忙开始这个呢?
到目前为止,我认为这个pesudo代码:
public class ThreadingTest extends Thread {
public HashMap<String, String > contents = new HashMap<String, String>();
public ThreadingTest(ArrayList<String> paths)
{
for(String s : paths)
{
// paths is paths to files.
// Have threading here for each path going to get contents from a
// file
//Not sure how to limit and start threads here
readFile(s);
Thread t = new Thread();
t.start();
}
}
public String readFile(String path) throws IOException
{
FileReader reader = new FileReader(path);
StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader(reader);
String line;
while ( (line=br.readLine()) != null) {
sb.append(line);
}
return textOnly;
}
}
完成线程处理的任何帮助。谢谢
答案 0 :(得分:7)
简答:按顺序读取文件。磁盘I / O不能很好地并行化。
长答案:如果磁盘擅长随机访问(SSD磁盘)或者文件放在多个不同的磁盘上,线程可能会提高读取性能,但如果它们不是你,你可能最终会遇到大量缓存未命中并等待磁盘寻找正确的读取位置。 (即使你的磁盘擅长随机访问,你仍然可能会在那里结束。)
如果您想衡量而不是猜测,请使用Executors.newFixedThreadPool
创建一个ExecutorService
,它可以并行读取您的文件。尝试不同的线程数,但如果每个物理磁盘的一个读取器线程为您提供最佳性能,请不要感到惊讶。
答案 1 :(得分:1)
这是线程池的典型任务。请参阅此处的教程:http://download.oracle.com/javase/tutorial/essential/concurrency/pools.html
答案 2 :(得分:1)
import java.io.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
public class PooledFileProcessing {
private Map<String, String> contents = Collections.synchronizedMap(new HashMap<String, String>());
// Integer.MAX_VALUE items max
private LinkedBlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>();
private ExecutorService executor = new ThreadPoolExecutor(
5, // five workers by default
20, // up to twenty workers
1, TimeUnit.MINUTES, // idle thread dies in one minute
workQueue
);
public void process(final String basePath) {
visit(new File(basePath));
System.out.println(workQueue.size() + " jobs still in queue");
executor.shutdown();
try {
executor.awaitTermination(5, TimeUnit.MINUTES);
} catch (InterruptedException e) {
System.out.println("interrupted while awaiting termination");
}
System.out.println(contents.size() + " files indexed");
}
public void visit(final File file) {
if (!file.exists()) {
return;
}
if (file.isFile()) { // skip the dirs
executor.submit(new RunnablePullFile(file));
}
// traverse children
if (file.isDirectory()) {
final File[] children = file.listFiles();
if (children != null && children.length > 0) {
for (File child : children) {
visit(child);
}
}
}
}
public static void main(String[] args) {
new PooledFileProcessing().process(args.length == 1 ? args[0] : System.getProperty("user.home"));
}
protected class RunnablePullFile implements Runnable {
private final File file;
public RunnablePullFile(File file) {
this.file = file;
}
public void run() {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
StringBuilder sb = new StringBuilder();
String line;
while (
(line=reader.readLine()) != null &&
sb.length() < 8192 /* remove this check for a nice OOME or swap thrashing */
) {
sb.append(line);
}
contents.put(file.getPath(), sb.toString());
} catch (IOException e) {
System.err.println("failed on file: '" + file.getPath() + "': " + e.getMessage());
if (reader != null) {
try {
reader.close();
} catch (IOException e1) {
// ignore that one
}
}
}
}
}
}
答案 3 :(得分:0)
根据我的经验,线程有帮助 - 使用线程池并使用每个核心大约1..2个线程的值。
请注意哈希映射 - 考虑仅通过同步方法将数据放入地图。我记得我曾经在类似的项目中遇到过一些丑陋的问题,它们与中央哈希映射的并发修改有关。
答案 4 :(得分:0)
只是一些快速提示。
首先,为了让您开始使用线程,您应该只查看Runnable
接口或Thread
类。要创建一个线程,您必须使用类实现此接口,或者使用另一个类扩展此类。你也可以创建匿名线程,但我不喜欢那些可读性,除非它的东西超简单。
接下来,只是关于使用多个线程处理文本的一些注意事项,因为它恰好发生了我有一些经验!请记住,如果文件很大并且需要相当长的时间来处理您希望监视CPU的单个文件。根据我的经验,我在处理时进行了大量的计算和查找,这极大地增加了我的负载,所以最后我发现我只能创建与处理器一样多的线程,因为每个线程都是如此劳动密集。所以记住这一点,你想要监控每个线程对处理器的影响。
答案 5 :(得分:0)
如果所有文件都在同一个物理磁盘上,我不确定是否有线程可以真正加快进程。它甚至可以减慢速度,因为磁盘必须不断地从一个位置切换到另一个位置。