[英]Linux & Windows: Using Large Files to save physical memory
下午好,我们已经实现了C ++ cKeyArray类来测试是否可以使用大文件API来节省物理内存。 在Centos Linux测试期间,我们发现Linux File API与使用堆进行随机访问处理一样快。 这些是数字:对于一个2,700,000行的SQL数据库,其中每行的KeySize为62个字节,
使用LINUX File API的cKeyArray类BruteForceComparisons = 197275 BruteForceTimeElapsed = 1,763,504,445微秒每个BruteForce比较需要两次随机访问,因此每次随机访问所需的平均时间= 1,763,504,445微秒/(2 * 197275)= 4470微秒
堆,没有cKeyArray类
BruteForceComparisons = 197275 BruteForceTimeElapsed = 1,708,442,690微秒每次随机访问所需的平均时间= 4300微秒。
在32位Windows上,数字为
使用Windows File API的cKeyArray类BruteForceComparisons = 197275 BruteForceTimeElapsed = 9243787 Millisecs每次随机访问的平均时间为23.4 millisec
堆,没有cKeyArray类BruteForceComparisons = 197275 BruteForceTimeElapsed = 2,141,941毫秒,每次随机访问所需的平均时间为5.4毫秒
我们想知道为什么Linux cKeyArray号与Linux堆号一样好,而在32位Windows上,平均堆随机访问时间是cKeyArray Windows File API的4倍。 有什么方法可以加快Windows cKeyArray File API的速度吗?
以前,我们从Stack Overflow收到了许多有关使用Windows内存映射文件API的好建议。 根据这些堆栈溢出建议,我们实现了一个内存映射文件MRU缓存类,该类可正常运行。
因为我们想开发一个跨平台的解决方案,所以我们要进行尽职调查以了解为什么Linux File API这么快? 谢谢。 我们正在尝试在下面发布cKeyArray类实现的一部分。
#define KEYARRAY_THRESHOLD 100000000
// Use file instead of memory if requirement is above this number
cKeyArray::cKeyArray(long RecCount_,int KeySize_,int MatchCodeSize_, char* TmpFileName_) {
RecCount=RecCount_;
KeySize=KeySize_;
MatchCodeSize=MatchCodeSize_;
MemBuffer=0;
KeyBuffer=0;
MemFile=0;
MemFileName[0]='\x0';
ReturnBuffer=new char[MatchCodeSize + 1];
if (RecCount*KeySize<=KEYARRAY_THRESHOLD) {
InMemory=true;
MemBuffer=new char[RecCount*KeySize];
memset(MemBuffer,0,RecCount*KeySize);
} else {
InMemory=false;
strcpy(MemFileName,TmpFileName_);
try {
MemFile=
new cFile(MemFileName,cFile::CreateAlways,cFile::ReadWrite);
}
catch (cException e)
{
throw e;
}
try {
MemFile->SetFilePointer(
(int64_t)(RecCount*KeySize),cFile::FileBegin);
}
catch (cException e)
{
throw e;
}
if (!(MemFile->SetEndOfFile()))
throw cException(ERR_FILEOPEN,MemFileName);
KeyBuffer=new char[KeySize];
}
}
char *cKeyArray::GetKey(long Record_) {
memset(ReturnBuffer,0,MatchCodeSize + 1);
if (InMemory) {
memcpy(ReturnBuffer,MemBuffer+Record_*KeySize,MatchCodeSize);
} else {
MemFile->SetFilePointer((int64_t)(Record_*KeySize),cFile::FileBegin);
MemFile->ReadFile(KeyBuffer,KeySize);
memcpy(ReturnBuffer,KeyBuffer,MatchCodeSize);
}
return ReturnBuffer;
}
uint32_t cKeyArray::GetDupeGroup(long Record_) {
uint32_t DupeGroup(0);
if (InMemory) {
memcpy((char*)&DupeGroup,
MemBuffer+Record_*KeySize + MatchCodeSize,sizeof(uint32_t));
} else {
MemFile->SetFilePointer(
(int64_t)(Record_*KeySize + MatchCodeSize) ,cFile::FileBegin);
MemFile->ReadFile((char*)&DupeGroup,sizeof(uint32_t));
}
return DupeGroup;
}
在Linux上,操作系统会积极地将文件数据缓存在主内存中-因此,尽管您尚未为文件内容显式分配内存,但它们仍存储在RAM中。 这是一个不错的链接,其中包含有关页面高速缓存的更多信息-该描述仅缺少一件事,即大多数Linux文件系统实际上将标准I / O接口实现为页面高速缓存周围的薄包装。 这意味着即使您没有显式地对文件进行内存映射,系统仍将其视为已被内存映射的文件。 这就是为什么您会看到两种方法的性能大致相当的原因。
我建议将特定于平台的内容排除在外,并针对每个平台使用最快的方法。 请务必进行基准测试-永远不要对性能进行假设。
即使在Linux中,您的内存映射解决方案也应比文件解决方案快10倍之多。 那就是我在测试用例中经历的速度。
每个文件访问系统调用都需要数百个CPU周期才能完成。 您的程序可以用来完成实际工作的时间。
关于速度为何如此相似的一种解释可能是您以前没有使用过内存映射。 首次访问内存映射页时,必须将其分配给RAM的物理页并清零,或者如果它是磁盘文件,则必须将其从磁盘加载到RAM中。 所有这些都需要花费大量时间。
如果在使用前触摸(读取或写入一个值)每个4K RAM,您应该会看到内存映射中的速度显着提高。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.