最近,我遇到了一个关于微软实现CRTL的“有趣”问题tmpfile将临时文件放在根目录中,并完全忽略临时文件目录这对于没有根目录权限的用户(例如,在我们的集群上)有问题。此外,使用_tempnam将需要应用程序记住删除临时文件,如果不进行大量的返工,则无法执行此操作。
因此,我咬紧牙关,编写了所有IO例程(create_temp、read、write、seek、flush)的Win32版本,这些例程调用适当的方法。我注意到的一件事是图书馆现在糟糕的表现。
测试套件的结果:

CRTL:    4:30.05 elapsed
Win32:  11:18.06 elapsed

Stats measured in my routines:
Writes:  3129934 (   44,642,745,008 bytes)
Reads:    935903 (    8,183,423,744 bytes)
Seeks:   2205757 (2,043,782,657,968 bytes traveled)
Flushes:   92442

CRTL v.Win32方法的示例:
int io_write(FILE_POINTER fp, size_t words, const void *buffer)
{
#if !defined(USE_WIN32_IO)
    {
        size_t words_written = 0;

        /* read the data */
        words_written = fwrite(buffer, sizeof(uint32_t), words, fp);
        if (words_written != words)
        {
            return errno;
        }
    }
#else /* !defined(USE_WIN32_IO) */
    {
        DWORD bytesWritten;

        if (!WriteFile(fp, buffer, words * sizeof(uint32_t), &bytesWritten, NULL)
            || (bytesWritten != words * sizeof(uint32_t)))
        {
            return GetLastError();
        }
    }
#endif /* USE_WIN32_IO */

    return E_SUCCESS;
}

如您所见,它们实际上是相同的,但性能(在发布模式下)却大相径庭。花在WriteFileSetFilePointer上的时间使花在fwritefseeko上的时间相形见绌,这似乎违反直觉。
思想?
更新:perfmon注意到fflushFlushFileBuffers便宜约10倍,fwriteWriteFile慢约1.1倍最终的结果是巨大的性能损失,FlushFileBuffers的使用方式与fflush相同。从FILE_ATTRIBUTE_NORMALFILE_FLAG_RANDOM_ACCESS也没有变化。

最佳答案

我认为这可能是由于这个问题,在MSDN的FlushFileBuffers页面上描述:
由于磁盘缓存交互
在系统内
FlushFileBuffers函数可以是
每次使用后效率低下
写入磁盘驱动器设备时
正在单独执行写入操作。
如果应用程序正在执行
多次写入磁盘,还需要
确保关键数据写入
持久介质,应用程序
应该使用无缓冲I/O而不是
频繁调用FlushFileBuffers。
要为无缓冲I/O打开文件,
使用调用CreateFile函数
文件标志没有缓冲和
文件标志通过标志写入这个
防止文件内容
缓存元数据并将其刷新到
每次写入的磁盘更多
有关信息,请参见CreateFile。
一般来说,FlushFileBuffers是一个“昂贵的”操作,since it flushes everything in the write-back cache
FlushFileBuffers():此函数将刷新回写缓存中的所有内容
不知道缓存的哪个部分属于您的文件这需要很多时间,
取决于缓存大小和媒体速度有必要吗有
一个通过并写出脏页的线程,因此它可能不太
必要的。
我假设fflush不会刷新整个写回缓存。在这种情况下,它的效率要高得多,但这种效率存在潜在的数据丢失风险CRT的fflush源代码证实了这一点,因为_commit调用FlushFileBuffers

/* lowio commit to ensure data is written to disk */
if (str->_flag & _IOCOMMIT) {
        return (_commit(_fileno(str)) ? EOF : 0);
}

_commit的实施:
if ( !FlushFileBuffers((HANDLE)_get_osfhandle(filedes)) ) {
        retval = GetLastError();
}

09-26 17:59