当前位置: 首页 > 面试题库 >

真正在Java中强制文件同步/刷新

范修伟
2023-03-14
问题内容

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);
}


 类似资料:
  • 本文向大家介绍D3.js中强制异步文件读取同步的几种方法,包括了D3.js中强制异步文件读取同步的几种方法的使用技巧和注意事项,需要的朋友参考一下 发现问题 在使用d3.js时,我们经常会使用d3.csv()或者d3.json()函数来从文件中读取出数据,不幸的是,偶尔代码的结果并不是我们预料的那样。习惯了过程式编程的我开始的时候也是这样,最让人头疼的是javascript并不会告诉你问题出在哪里

  • 问题内容: 我们目前正处于非公开Beta测试阶段,因此仍在进行相当快速的更改,尽管显然随着使用量的增加,我们将放慢这个过程。话虽这么说,我们遇到的一个问题是,在我们推出新JavaScript文件的更新后,客户端浏览器仍然使用文件的缓存版本,而他们看不到更新。显然,在技术支持电话上,我们可以简单地通知他们进行刷新以确保他们从服务器获取最新文件,但是最好在此之前进行处理。 我们当前的想法是将版本号简单

  • 您可以通过 Bluetooth 连接,以无线方式,将数据从手表传输至 Polar Flow 应用程式。或者您可以使用 USB 端口和 FlowSync 软件,将手表与 Polar Flow 网络服务同步。若要在手表与 Flow 应用程式之间同步数据,您需要拥有 Polar 账户。如果您想将手表上的数据直接同步到网络服务,除了 Polar 账户,您还需要 FlowSync 软件。如果您已设置手表,已

  • 您可以通过 Bluetooth 连接,以无线方式,将数据从手表传输至 Polar Flow 应用程式。或者您可以使用 USB 端口和 FlowSync 软件,将手表与 Polar Flow 网络服务同步。若要在手表与 Flow 应用程式之间同步数据,您需要拥有 Polar 账户。如果您想将手表上的数据直接同步到网络服务,除了 Polar 账户,您还需要 FlowSync 软件。如果您已设置手表,已

  • 您可以使用 FlowSync 软件通过 USB 端口传输来自 A370 的数据,或使用 Flow 应用程式通过 Bluetooth Smart® 进行无线传输。若要在 A370 和 Flow 网络服务与应用程式之间同步数据,您需要拥有 Polar 账户和 FlowSync 软件。如果您在 flow.polar.com/start中设置了 A370,说明您已创建了该账户并下载了该软件。当您开始使用

  • 问题内容: 我创建了一个小型Java servlet,其目的很简单:调用它后,它将执行以下步骤: 从本地文件系统读取文件foo.json 处理文件中的数据并对其进行一些更改 将更改写回文件 代码的简化版: 现在,我面临一个问题,即可能有两个或多个对servlet的http请求几乎同时调用servlet。为了避免对同一文件进行多次并行写访问,我需要以某种方式进行同步。根据我对servlet生命周期过