真正在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

回到顶部