在工作中,我们在 Jenkins 的帮助下定期在几台构建机器上运行我们的单元测试。其中一个单元测试打开一个带有 的文件,并对该文件FILE_FLAG_WRITE_THROUGH
进行数万次调用。WriteFile
为什么这样做与这个问题无关。仅在其中一台构建机器上,此测试不断超时。经过一番调查,结果发现其根本原因是每次调用都WriteFile
被阻塞(线程被切换出去,然后又被切换进来),使得测试运行速度大大降低。奇怪的是,当在这台机器上手动启动测试时,WriteFile
并没有阻塞,因此测试没有超时。
经过数小时的反复试验,我找到了一个“解决方法”:在受影响的机器上,如果 Jenkins 是使用任务计划程序启动的,WriteFile
被阻止,如果它是手动启动的,或者通过将 BAT 文件放在 Startup 文件夹中,它没有。我认为我需要进行更多调查,所以我创建了一个最小的 repro,一个用 . 打开文件的小程序,FILE_FLAG_WRITE_THROUGH
并使用随机数据调用WriteFile
它 10000 次。有了这个最小的复制,WriteFile
无论我如何启动它,都会不断地阻塞。我真的很困惑,所以在这里我要求对这种行为进行任何解释。我进行测试的所有机器都有 SATA 驱动器,默认设置(写入缓存和 Windows 写入缓存刷新已启用)。
首先对我来说,它甚至不是 100% 清楚FILE_FLAG_WRITE_THROUGH
应该做什么。互联网上的信息表明,一个特殊的标志被传递给设备,要求它在写入后刷新其缓存。根据Raymond Chen(和其他一些人)的说法,现在这几乎无关紧要,因为大多数 SATA 驱动器由于性能原因默默地忽略了这个标志。在“应该或不应该阻止”方面,此页面明确指出 withFILE_FLAG_WRITE_THROUGH
WriteFile
应该阻止:
在将数据写入文件之前,write 调用不会返回。
你知道为什么我会看到这种奇怪的行为(不一致)吗?我该如何进一步调查?