这是某种长篇文章,所以我要感谢阅读。 我的应用程序应该处理很多声音文件,比方说4000+。我的第一种方法是加载一定数量(比方说200mb)的声音数据,处理它,写入然后“空”数据让gc释放它。但是,通过内部网加载数据的事实,这似乎不是“最好”的方式。 (文件访问速度很慢)计算应从第一个加载的文件开始。为了实现这个目标,我将概念改为某种“生产者/消费者”(我认为)。到目前为止,这是我的课程:
阅读器/生产
public class ReaderThread extends Thread {
List<Long> files;
ConcurrentLinkedQueue<Long> loaded = new ConcurrentLinkedQueue<Long>();
boolean finished = false;
public ReaderThread( List<Long> soundFiles) {
this.files = soundFiles;
}
@Override
public void run() {
Iterator<Long> it = files.iterator();
while(it.hasNext()) {
Long id = it.next();
if (FileLoader.load(id)) {
loaded.add(id);
}
}
finished = true;
}
public Long getNextId() {
while(loaded.isEmpty()) {
if( finished ) {
return null;
}
}
Long id = loaded.poll();
return id;
}
}
这是作家/(非消费者)
public class WriterThread extends Thread {
ConcurrentLinkedQueue<Long> loaded = new ConcurrentLinkedQueue<Long>();
String directory;
boolean abort = false;
public WriterThread(String directory) {
this.directory = directory;
}
@Override
public void run() {
while(!(abort&&loaded.isEmpty())) {
if(!loaded.isEmpty()) {
Long id = loaded.poll();
FileWriter.write(id, directory);
FileManager.unload(id);
}
}
}
public synchronized void submit(Long id) {
loaded.add(id);
}
public synchronized void halt() {
abort = true;
}
}
这是所有事物聚集在一起的部分:
// Forgive me the "t" and "w". ;-)
t = new ReaderThread(soundSystem,soundfilesToProcess);
w = new WriterThread(soundSystem,outputDirectory );
t.start();
w.start();
long start = System.currentTimeMillis();
while(!abort) {
Long id = t.getNextId();
if(id!=null) {
SoundFile soundFile = soundSystem.getSoundfile(id);
ProcessorChain pc = new ProcessorChain(soundFile, getProcessingChain(), w);
Future<List<ProcessorResult>> result = es.submit(pc);
results.add(result);
}else {
break;
}
}
for( Future<List<ProcessorResult>> result : results) {
List<ProcessorResult> tempResults;
try {
tempResults = result.get();
processResults(tempResults);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
w.halt();
“ProcessorChain”是一个可运行的。 es.submit - &gt; “es”是一个CachedThreadPool。
首先我需要知道的是天气与否,这种方法是“好的”,或者更像是“非常规”。它似乎工作得很好,但我对编写器线程几乎没有问题,似乎在某些情况下并非所有文件都被写入。编写器线程的submit方法在完成工作后由ProcessorChain调用。 第二件事就是安全。我错过了什么吗?
答案 0 :(得分:3)
我相信如果每个线程读取,处理然后写一个完整的声音文件(每个文件一个线程),它将会(很多)更简单。
您使用can Java thread pools并让操作系统/ Java VM将读取/进程/写入与多个文件并行化以提高效率。我可能错了,但从你所描述的更简单的解决方案就足够了,如果需要进一步的改进,你可以衡量你的瓶颈。
答案 1 :(得分:1)
我认为这种方法通常是正常的(一个用于读取输入的线程,一个用于写入输出,一个用于处理)。
一些建议:
1 - 你可能想要使用信号量而不是让你的线程在一个恒定的循环中旋转。例如,使用信号量,您的写入线程将阻塞,直到文件实际可用于写入。目前它会旋转,当没有什么可写的时候可能会浪费1/3的cpu周期。
2 - 您可能希望显式创建工作线程而不是在主线程上执行工作。这样,您可以让多个线程同时进行处理。 这可能已经是ProcessorChain正在做的事情,但是从片段中看不清楚。