跟安全软件无关,哪怕把所有安全软件都关了,Windows也是一样慢,就是文件系统的问题。
先放结论:在缓存没有耗尽的情况下,Linux的小文件访问性能要远远高于Windows,这是Windows文件系统和整个操作系统缓存策略的问题。
各种性能测试软件,往往都是在关闭缓存或者耗尽缓存以后才开始统计的,所以性能测试上NTFS跟EXT4之间看不出明显的差异。
一些比较直观的证据:
NTFS-3G在Linux上的性能是要好于NTFS在Windows上的性能的(同样的硬件);
批量删除小文件(使用命令行),EXT4的性能远远高于NTFS(同样硬件);
从主机往U盘上写入小文件(1M以内),Linux实际上是立即返回(只写到缓存里),Windows则是真正写到了盘里,拔盘的话可以看到Linux的盘上没有任何数据。
注意,这里只强调用户体验的性能,而不是测试跑分。Linux是有可能丢失更多的文件,但丢失文件跟性能话题无关。
有人宁可相信自己的直觉,也不肯动手做一下实验,在这个回答的最后有一段代码测试,有兴趣的可以在自己机器上做一下实验。
放一段XP泄漏的NTFS代码,在DriverEntry里,根据系统内存大小来确定一些cache之类的大小:
switch ( MmQuerySystemSize() ) { case MmSmallSystem: NtfsMcbHighWaterMark = 1000; NtfsMcbLowWaterMark = 500; NtfsMcbCurrentLevel = 0; break; case MmMediumSystem: NtfsMcbHighWaterMark = 4000; NtfsMcbLowWaterMark = 2000; NtfsMcbCurrentLevel = 0; break; case MmLargeSystem: default: NtfsMcbHighWaterMark = 16000; NtfsMcbLowWaterMark = 8000; NtfsMcbCurrentLevel = 0; break; }
通过那个MmQuerySystemSize函数,来决定用多大的cache,但是看看MmQuerySystemSize函数的代码实现里有一段注释:
MM_SYSTEMSIZE MmQuerySystemSize( VOID ) { // // 12Mb is small // 12-19 is medium // > 19 is large // return MmSystemSize; }
19M以上就算大内存了,可见Windows对内存的使用是多么保守。另外NtfsInitializeNtfsData里也可以看到cache的大小,在如今内存上GB的时代,Windows的文件系统缓存还停留在十几MB的范围,这种情况下你不能指望Windows的文件系统性能有多好。
特别提醒:19M指的是系统总内存大于19M,就认为是大内存。当然了,这段注释可能不准,有兴趣的可以看这里:
if (MmNumberOfPhysicalPages >= ((32*1024*1024)/PAGE_SIZE)) { // // If we are on a workstation, 32Mb and above are considered // large systems. // if (MmProductType == 0x00690057) { MmSystemSize = MmLargeSystem; } else { // // For servers, 64Mb and greater is a large system // if (MmNumberOfPhysicalPages >= ((64*1024*1024)/PAGE_SIZE)) { MmSystemSize = MmLargeSystem; } }
相比之下,Linux上来就能先保留一半物理内存作为整体的缓存使用,所以在操作的文件比较少的情况下,Windows和Linux的文件系统差距非常明显。只有当缓存全部耗尽了,两者性能才会比较接近(当然了,小文件性能,Windows还是一样的差,系统框架设计的问题)。
没有XP源码的,可以去WRK上看FAT的源码。FAT32驱动,在大内存配置下,最多的延迟关闭的文件数量是256个,这样的文件系统,性能要是好了才奇怪。
有人说,我这个是XP的代码,现在WIN10都不这样了,验证的方法很简单,找WIN10的驱动反汇编一下:
FAT对应的驱动是FASTFAT.SYS:
FatMaxDelayedCloseCount最大值仍然是256
对于NTFS,代码变化有点大,就贴一段汇编:
INIT:00000001C0295321 mov edx, cs:dword_1C00951DC INIT:00000001C0295327 imul eax, r14d, 3E80h INIT:00000001C029532E shl rdx, 3 INIT:00000001C0295332 mov cs:NtfsMcbCurrentLevel, ebx INIT:00000001C0295338 mov cs:NtfsMcbHighWaterMark, eax INIT:00000001C029533E imul eax, r14d, 1F40h INIT:00000001C0295345 mov cs:NtfsMcbLowWaterMark, eax INIT:00000001C029534B mov eax, 0FFFFFFFFh INIT:00000001C0295350 cmp rdx, rax INIT:00000001C0295353 jbe short loc_1C029537B INIT:00000001C0295355 xor r9d, r9d
关键值:imul eax, r14d, 3E80h,0x3e80 ==> 16000,NtfsMcbHighWaterMark跟XP时代不变。(R14D默认值是1,代码比较绕,就不全贴出来了)。
这个值,微软的文档写的是允许改的,可以改成2:
2的话也就是16000*2,也没大多少。
评论里 @轻语碎雷 说NTFS的代码改过,跟XP时代确实改过,但本质上还是拿16000乘以注册表项HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlFileSystem下的:NtfsMemoryUsage,如果这个值是0,则默认是乘以1,所以本质上跟XP没什么差别。
反汇编WIN10的NTFS.SYS即可得到相应的结论。
我不知道为什么有人容不得说Windows文件系统的缺陷。Windows文件系统(包括IO框架)有性能问题是实际存在的,这个问题从NT时代一开始就有,文件系统里fastio这些接口本质上都是为了解决一部分文件系统的性能问题。
Windows文件系统另一个相似的问题:
另外,不怕丢数据的可以做一个实验,在Linux上写NTFS盘,看看性能怎么样,反正我试过的结果是比Windows自己的NTFS还要快一些。
Windows文件系统(含块设备驱动)的cache设计整体上是偏向于保守的,上面的例子只是说明文件系统的缓存设计,实际上包括块设备驱动这一层,Windows也一样存在大量保守的设计。由于兼容性的问题,Windows并不轻易更改这方面的设计,因此,在系统有大量内存的情况下,Windows的文件系统性能确实不如Linux。
Linux的激进的缓存策略并不一定永远都是好用的,比如Linux上U盘更容易丢失数据,Windows针对U盘的写策略默认是write-through的,写完拔盘很少丢文件。
企业客户们使用Windows,更重视的是Windows的兼容性以及易用性。当然,Windows的游戏(图形)性能确实出众。
任何系统都有优点和缺点,不管是Windows还是Linux。
有人不相信Windows文件系统有多慢,动手写一段代码就好了:
#ifdef _WIN32 #define _CRT_SECURE_NO_WARNINGS #endif #include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> #ifndef _WIN32 #include <unistd.h> #endif int main(int argc, char * argv[]) { FILE* fp; clock_t st, ed; int count; char fname[256] = { 0 }; if (argc != 2) { printf("Usage %s <count>
", argv[0]); return -1; } count = atoi(argv[1]); st = clock(); for (int i = 0; i < count; i++) { sprintf(fname, "test%d", i); fp = fopen(fname, "wb"); fwrite(fname, sizeof(fname), 1, fp); fclose(fp); } for (int i = 0; i < count; i++) { sprintf(fname, "test%d", i); #ifdef _WIN32 _unlink(fname); #else unlink(fname); #endif } ed = clock(); printf("Clock = %d, %d, %d, %d, %d", ed - st, st, ed, CLOCKS_PER_SEC, (ed - st) / CLOCKS_PER_SEC); return 0; }
以上代码,在我的电脑上,参数传入10000(也就是创建、删除10000个小文件)Windows运行结果如下:
Clock = 6053, 0, 6053, 1000, 6
耗时6秒多。
在同样的环境下,用virtualbox虚拟机(fedora33)编译运行,结果如下
Clock = 642972, 2298, 645270, 1000000, 0
也就是说Windows上用了6秒,Linux上用了0.6秒,整整差了10倍,而我这个环境里,Linux是虚拟机。自己去判断一下真实的Linux比Windows能快多少。测试文件越少,差距越大。(注:不同机器上测得的数据差别很大,我拿到的最大的性能差距是:Windows:14秒、Linux虚拟机:0.4秒)
加上Windows上一些安全软件的影响,小文件操作性能差距100倍以上太正常了。
我相信,对于有些人来说,哪怕你把数据丢到他眼前,他还会找各种理由:
实际编译肯定没10000个文件这么多;
你的测试也没达到2分钟那么慢;
你这个盘太慢了;
你肯定没关杀毒软件;
……
对于这些评论,我想说,你们说的都对,Windows的文件系统是最快的文件系统,肯定是用户用的不对。
这个问题问得很好啊,我的建议是看今年年会的摘要集:
中国化学会第32届学术年会 - 论文检索系统 - 中国化学会
可以看到有很多分会,不过计算化学分布得比较散,夹杂在各个分会中。各分会的主题可以从这里找到,可能相关的包括:
有一些主题是理论计算夹杂着实验的,还需要仔细辨别。回到摘要集,以第一分会为例:
中国化学会第32届学术年会摘要集-第一分会:物理化学前沿 - 论文检索系统 - 中国化学会
可以看到题目和单位全都标出来了,而且还可以下载。
显然,能找到相关方向的摘要的单位,就是开设了相关方向的院校,甚至还能精确到具体的某个课题组。