我的主线程中有一个函数,它会将一些数据写入磁盘。我不希望我的主线程卡住(磁盘I/O的高度延迟)和创建一个新线程仅仅是为了写是一种过度。我决定使用ExecutorService.
ExecutorService executorService = Executors.newFixedThreadPool(3);
Future future = executorService.submit(new Callable<Boolean>() {
public Boolean call() throws Exception {
logger.log(Level.INFO, "Writing data to disk");
return writeToDisk();
}
});writeToDisk是将写入磁盘的函数。
这是个不错的方法吗?如果有的话,谁能推荐更好的方法吗?
更新:数据大小将大于100 MB。磁盘带宽为40 MBps,因此写入操作可能需要几秒钟。我不希望调用函数卡住,因为它必须做其他的工作,所以,我正在寻找一种方法来安排磁盘I/O异步执行调用线程。
我需要委派任务,忘记它!
发布于 2014-11-13 08:43:47
我知道有两种方法,一种是旋转线程(或者像你一样使用线程池),另一种是内存映射一个文件并让操作系统来管理它。这两种方法都是很好的方法,内存映射文件的速度比使用Java编写器/流快10倍,而且它不需要单独的线程,所以在性能是关键时,我常常倾向于这样做。
无论哪种方式,作为一些优化磁盘写入的技巧,请尽可能预先分配文件。调整文件的大小是很昂贵的。旋转磁盘不喜欢查找,SSD不喜欢更改以前编写的数据。
我写了一些基准测试,以帮助我探索这一领域一段时间前,您可以自己运行基准。其中有一个内存映射文件的例子。
发布于 2014-11-13 09:02:07
不管怎么说,您的代码看起来都不错,我从新的非阻塞IO中使用了AsynchronousFileChannel。该实现通过MappedByteBuffer通过FileChannel使用。“它可能会给你表演,”克里斯说。下面是一个简单的例子:
public static void main(String[] args) {
String filePath = "D:\\tmp\\async_file_write.txt";
Path file = Paths.get(filePath);
try(AsynchronousFileChannel asyncFile = AsynchronousFileChannel.open(file,
StandardOpenOption.WRITE,
StandardOpenOption.CREATE)) {
asyncFile.write(ByteBuffer.wrap("Some text to be written".getBytes()), 0);
} catch (IOException e) {
e.printStackTrace();
}
}发布于 2018-06-14 10:56:35
我同意zbek使用非阻塞方法。然而,正如迪安·希勒所指出的,我们不能在使用资源进行尝试之前就关闭AsynchronousFileChannel,因为它可能会在写入完成之前关闭通道。
因此,我将在CompletionHandler上添加一个asyncFile.write(…,new CompletionHandler< >(){…}来跟踪完成,并在写操作结束后关闭底层AsynchronousFileChannel。为了简化使用,我将CompletionHandler转换为一个CompletableFuture,我们可以很容易地用一个连续的链子在写完后做我们想做的任何事情。最后一个辅助方法是CompletableFuture write(ByteBuffer bytes),它在完成相应的写操作后返回最终文件索引的CompletableFuture。我将所有这些逻辑放在一个可以像这样使用的辅助类AsyncFiles中:
Path path = Paths.get("output.txt")
AsyncFiles
.write(path, bytes)
.thenAccept(index -> /* called on completion from a background thread */)https://stackoverflow.com/questions/26903853
复制相似问题