下午好,我们已经实现了一个C ++ cKeyArray类来测试我们是否可以使用Large File API来节省物理内存。在Centos Linux测试期间,我们发现Linux File API与使用堆进行随机访问处理一样快。以下是数字:对于2,700,000行SQL数据库,其中每行的KeySize为62字节,
使用LINUX File API的cKeyArray类 BruteForceComparisons = 197275 BruteForceTimeElapsed = 1,763,504,445微秒 每个BruteForce Comparisons需要两次随机访问,每次随机访问所需的平均时间= 1,763,504,445微秒/(2 * 197275)= 4470微秒
堆,没有cKeyArray类
BruteForceComparisons = 197275 BruteForceTimeElapsed = 1,708,442,690microsecs 每次随机访问所需的平均时间= 4300微秒。
在32位Windows上,数字为,
使用Windows File API的cKeyArray类 BruteForceComparisons = 197275 BruteForceTimeElapsed = 9243787毫秒 每次随机访问的平均时间是23.4毫秒
堆,没有cKeyArray类 BruteForceComparisons = 197275 BruteForceTimeElapsed = 2,141,941毫秒 每次随机访问所需的平均时间为5.4毫秒
我们想知道为什么Linux cKeyArray数字和Linux堆数一样好,而在32位Windows上,平均堆随机访问时间是cKeyArray Windows文件API的4倍。有什么方法可以加快Windows cKeyArray文件API的速度吗?
之前,我们收到了Stack Overflow关于使用Windows内存映射文件API的许多好建议。基于这些Stack Overflow建议,我们实现了一个内存映射文件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;
}
答案 0 :(得分:5)
在Linux上,操作系统主动将文件数据缓存在主内存中 - 因此,尽管您没有为文件内容明确分配内存,但它们仍然存储在RAM中。这里有一些关于page cache的更多信息的合适链接 - 该描述中只缺少一件事,即大多数Linux文件系统实际上将标准I / O接口实现为页面缓存周围的薄包装器。这意味着,即使您没有显式内存映射文件,系统仍然将其视为封装下的内存映射。这就是为什么你看到两种方法的表现大致相同的原因。
我的第二个建议是将平台特定的东西排除在外,并使用每个平台最快的方法。一定要做基准测试 - 不要对性能做出假设。
答案 1 :(得分:2)
即使在Linux中,您的内存映射解决方案也应该比文件解决方案快10倍。这是我在测试用例中遇到的速度。
每个文件访问系统调用都需要数百个CPU周期才能完成。你的程序可以用来做实际工作的时间。
速度相似的一个原因可能是你以前没有使用过你的记忆图。当第一次访问内存映射页面时,必须将其分配给RAM的物理页面并将其清零,或者如果它是磁盘文件,则必须将其从磁盘加载到RAM中。所有这些都需要相当长的时间。
如果在使用之前触摸(读取或写入值)每个4K的RAM,您应该会看到内存映射中的速度显着增加。