真正在Java中强制文件同步/刷新
Java 如何 将写入文件的数据与块设备进行刷新/同步。
我用NIO尝试了这段代码:
FileOutputStream s = new FileOutputStream(filename)Channel c = s.getChannel()
while(xyz)
c.write(buffer)
c.force(true)
s.getFD().sync()
c.close()
我认为c.force(true)与s.getFD()。sync()一起应该足够了,因为强制状态的文档
强制对此通道文件的任何更新都写入包含它的存储设备。如果此通道的文件位于本地存储设备上,则当此方法返回时,可以保证自创建此通道以来,或自上次调用此方法以来,对该文件所做的所有更改都将被写入该设备。这对于确保在系统崩溃时不会丢失关键信息很有用。
同步状态说明文件:
强制所有系统缓冲区与基础设备同步。在此FileDescriptor的所有修改后的数据和属性都已写入相关设备之后,此方法返回。特别是,如果此FileDescriptor引用物理存储介质,例如文件系统中的文件,则在与该FileDesecriptor关联的缓冲区的所有内存中已修改副本已写入物理介质之前,同步不会返回。sync是由需要物理存储(例如文件)处于已知状态的代码使用的。
这两个调用应该足够了。是吗?我想不是。
背景:我使用C / Java进行了较小的性能比较(2 GB,顺序写入),Java版的速度是C版的两倍,并且可能比硬件(单个HD上的120 MB /
s)快。我还尝试与Runtime.getRuntime()。exec(“ sync”)执行命令行工具同步,但这并没有改变行为。
导致70 MB / s的C代码是(使用低级API(打开,写入,关闭)不会有太大变化):
FILE* fp = fopen(filename, "w");while(xyz) {
fwrite(buffer, 1, BLOCK_SIZE, fp);
}
fflush(fp);
fclose(fp);
sync();
没有最终的同步请求;我得到了不切实际的值(超过1 GB的主内存性能)。
为什么C和Java之间有如此大的差异?有两种可能:我没有用Java正确同步数据,或者由于某种原因C代码不是最佳的。
更新:我已经使用“ strace -cfT cmd”完成了strace运行。结果如下:
C(低阶API):MB / s 67.389782
%时间秒usecs / call调用错误syscall------ ----------- ----------- --------- --------- ---- ------------
87.21 0.200012 200012 1 fdatasync
11.05 0.025345 1 32772写
1.74 0.004000 4000 1同步
C(高级API):MB / s 61.796458
%时间秒usecs / call调用错误syscall------ ----------- ----------- --------- --------- ---- ------------
73.19 0.144009 144009 1同步
26.81 0.052739 1 65539写
Java(1.6 SUN JRE,java.io API):MB /秒128.6755466197537
%时间秒usecs / call调用错误syscall------ ----------- ----------- --------- --------- ---- ------------
80.07 105.387609 3215 32776写
2.58 3.390060 3201 1059已读
0.62 0.815251 815251 1 fsync
Java(1.6 SUN JRE,java.nio API):MB / s 127.45830221558376
5.52 0.980061 490031 2 fsync 1.60 0.284752 9 32774写
0.00 0.000000 0 80关闭
时间值似乎仅是系统时间,因此毫无意义。
更新2:我切换到另一台服务器,重新启动,并使用新的格式化的ext3。现在,我与Java和C之间的区别只有4%。我根本不知道出了什么问题。有时情况很奇怪。在写这个问题之前,我应该尝试用另一个系统进行测量。抱歉。
更新3:总结答案:
- 对于Java NIO,使用c.force(true),然后使用s.getFD()。sync(),对于Java的流API,使用s.flush()和s.getFD()。sync()。对于C语言中的高级API,请不要忘记同步。lush将数据提交到OS,但没有将数据带到块设备。
- 使用strace分析命令执行的系统调用
- 在发布问题之前交叉检查您的结果。
回答:
您需要向我们详细介绍硬件和操作系统,以及特定的Java版本。您如何测量此吞吐量?
您是正确的,强制/同步应将数据强制输出到物理介质。
这是副本的原始版本。在Intel Mac上与gcc 4.0一起编译,应该干净。
/* rawcopy -- pure C, system calls only, copy argv[1] to argv[2] *//* This is a test program which simply copies from file to file using
* only system calls (section 2 of the manual.)
*
* Compile:
*
* gcc -Wall -DBUFSIZ=1024 -o rawcopy rawcopy.c
*
* If DIRTY is defined, then errors are interpreted with perror(3).
* This is ifdef'd so that the CLEAN version is free of stdio. For
* convenience I'm using BUFSIZ from stdio.h; to compile CLEAN just
* use the value from your stdio.h in place of 1024 above.
*
* Compile DIRTY:
*
* gcc -DDIRTY -Wall -o rawcopy rawcopy.c
*
*/
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <stdlib.h>
#include <unistd.h>
#if defined(DIRTY)
# if defined(BUFSIZ)
# error "Don't define your own BUFSIZ when DIRTY"
# endif
# include <stdio.h>
# define PERROR perror(argv[0])
#else
# define CLEAN
# define PERROR
# if ! defined(BUFSIZ)
# error "You must define your own BUFSIZ with -DBUFSIZ=<number>"
# endif
#endif
char * buffer[BUFSIZ]; /* by definition stdio BUFSIZ should
be optimal size for read/write */
extern int errno ; /* I/O errors */
int main(int argc, char * argv[]) {
int fdi, fdo ; /* Input/output file descriptors */
ssize_t len ; /* length to read/write */
if(argc != 3){
PERROR;
exit(errno);
}
/* Open the files, returning perror errno as the exit value if fails. */
if((fdi = open(argv[1],O_RDONLY)) == -1){
PERROR;
exit(errno);
}
if((fdo = open(argv[2], O_WRONLY|O_CREAT)) == -1){
PERROR;
exit(errno);
}
/* copy BUFSIZ bytes (or total read on last block) fast as you
can. */
while((len = read(fdi, (void *) buffer, BUFSIZ)) > -1){
if(len == -1){
PERROR;
exit(errno);
}
if(write(fdo, (void*)buffer, len) == -1){
PERROR;
exit(errno);
}
}
/* close and fsync the files */
if(fsync(fdo) ==-1){
PERROR;
exit(errno);
}
if(close(fdo) == -1){
PERROR;
exit(errno);
}
if(close(fdi) == -1){
PERROR;
exit(errno);
}
/* if it survived to here, all worked. */
exit(0);
}
以上是 真正在Java中强制文件同步/刷新 的全部内容, 来源链接: utcz.com/qa/419359.html