如何使 CreateFile 尽可能快
Posted
技术标签:
【中文标题】如何使 CreateFile 尽可能快【英文标题】:How to make CreateFile as fast as possible 【发布时间】:2011-11-17 20:38:19 【问题描述】:我需要在启动时读取数千个小文件的内容。在 linux 上,只使用 fopen 和阅读速度非常快。在 Windows 上,这发生得非常缓慢。
我已切换到使用 ReadFileEx 使用重叠 I/O(异步 I/O),当数据准备好读取时,Windows 会执行回调。
但是,实际上对 CreateFile 本身的数千次调用仍然是一个瓶颈。请注意,我提供自己的缓冲区,打开 NO_BUFFERING 标志,提供 SERIAL 提示等。但是,对 CreateFile 的调用需要 10 秒,而在 linux 上一切都完成得更快。
有什么办法可以让这些文件准备好以便更快地阅读?
对 CreateFile 的调用是:
hFile = CreateFile(szFullFileName,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING | FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
【问题讨论】:
有可能是文件系统的瓶颈,是否可以使用平面文件而不是读取数千个小文件? Windows 在处理一个目录中的大量文件方面是出了名的糟糕,如果这是您的情况。多线程是一种选择,所以您将有 10 个线程同时进行读取? 你应该看看这个问题***.com/questions/197162/… 嗨,我们有 12,000 个文件,而不是数百万个。我们只关心阅读信息,而不是编写信息。是的,文件系统很可能是瓶颈。不,这些文件并不都在一个目录中,它们分散在大约 300 个目录中。 您是否运行了防病毒软件?您是否尝试过从扫描中排除相关文件夹? 【参考方案1】:与ntdll.dll
中的内核系统调用NtCreateFile
相比,kernel32.dll
中的CreateFile
有一些额外的开销。这是CreateFile
调用以请求内核打开文件的真正函数。如果您需要打开大量文件,NtOpenFile
将通过避免 Win32 具有的特殊情况和路径转换(无论如何不适用于目录中的一堆文件)来提高效率。
NTSYSAPI NTSTATUS NTAPI NtOpenFile(OUT HANDLE *FileHandle, IN ACCESS_MASK DesiredAccess, IN OBJECT_ATTRIBUTES *ObjectAttributes, OUT IO_STATUS_BLOCK *iostatusBlock, IN ULONG ShareAccess, IN ULONG OpenOptions);
HANDLE Handle;
OBJECT_ATTRIBUTES Oa = 0;
UNICODE_STRING Name_U;
IO_STATUS_BLOCK IoSb;
RtlInitUnicodeString(&Name_U, Name);
Oa.Length = sizeof Oa;
Oa.ObjectName = &Name_U;
Oa.Attributes = CaseInsensitive ? OBJ_CASE_INSENSITIVE : 0;
Oa.RootDirectory = ParentDirectoryHandle;
Status = NtOpenFile(&Handle, FILE_READ_DATA, &Oa, &IoSb, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SEQUENTIAL_ONLY);
主要缺点:Microsoft 不支持在用户模式下使用此 API。也就是说,等效函数 is documented for kernel mode use 并且自 1993 年第一次发布 Windows NT 以来没有改变。
NtOpenFile
还允许您打开相对于现有目录句柄(示例中为 ParentDirectoryHandle)的文件,这将减少定位目录时的一些文件系统开销。
最后,正如 Carey Gregory 所说,NTFS 在处理包含大量文件的目录时可能太慢了。
【讨论】:
关于 NTFS “慢”的说法和关于 NtCreateFile 比 CreateFile 快的说法都不是真的——两者都是完全虚构的。除非有人为此发布一些证据,否则我将不得不称之为废话——除了几个 CPU 周期外,这两个函数的夜间行为都相同,并且 NTFS 是一个中等速度的文件系统。 见***.com/questions/197162/… 是的......那没有任何证据。没有数据。 同意,可以使用进程监视器为这两个函数找到matching set of parms。 CreateDirectoryW(同样的事情)做了更多的处理,但是在设置和管理 NTCreatedFIle 的结构时使用的额外开销几乎是相同的效果。【参考方案2】:在发布 Create 文件之前,尝试在 MFT 中有效地进行分页。这可以通过发出 FSCTL_ENUM_USN_DATA 来完成。
【讨论】:
以上是关于如何使 CreateFile 尽可能快的主要内容,如果未能解决你的问题,请参考以下文章
Windows下createfile函数用GENERIC_READ访问模式打不开磁盘