这是一个将n位写入二进制文件的函数。
参数:
第一版的功能:
void WriteBitsToFile(unsigned long long Data, unsigned Length, std::ofstream & OutFile) {
static unsigned long long BitBuffer = 0;
static unsigned BitCounter = 0;
for (unsigned i = Length; i --; ) {
(BitBuffer <<= 1) |= ((Data >> i) & 0x1);
BitCounter ++;
if (BitCounter == 64) {
OutFile.write((char *) & BitBuffer, sizeof(BitBuffer));
BitCounter = 0;
}
}
}
第二版:
void WriteBitsToFile(unsigned long long Data, unsigned Length, std::ofstream & OutFile) {
static unsigned long long BitBuffer = 0;
static unsigned FreeBitCounter = sizeof(BitBuffer) << 3;
Data &= (1 << Length) - 1;
if (FreeBitCounter > Length) {
BitBuffer |= (Data << (FreeBitCounter -= Length));
} else if (FreeBitCounter < Length) {
BitBuffer |= (Data >> (Length -= FreeBitCounter));
OutFile.write((char *) & BitBuffer, sizeof(BitBuffer));
BitBuffer = Data << ((sizeof(BitBuffer) << 3) - Length);
FreeBitCounter = (sizeof(BitBuffer) << 3) - Length;
} else {
BitBuffer |= Data;
OutFile.write((char *) & BitBuffer, sizeof(BitBuffer));
BitBuffer = 0; FreeBitCounter = (sizeof(BitBuffer) << 3);
}
}
他们都做了这个工作,但第二个比第一个快。有什么想让它更快?
谢谢大家的帮助!
答案 0 :(得分:1)
我首先要删除静态 函数体中的变量。 他们有点慢,应该测试 他们的状态(已经初始化或 不)每个函数调用。只是 将它们移出功能范围。
为什么要使用这么短的缓冲区?您确定需要将每个unsigned long long写入文件吗?我建议使用像unsigned char buffer[1024]
这样的东西。
然后你应该考虑如何摆脱其他“如果陈述”。
答案 1 :(得分:1)
而不是write()
来电,请尝试以下方法:
OutFile.rdbuf()->sputn((char *) & BitBuffer, sizeof(BitBuffer));
答案 2 :(得分:0)
打开文件可能比写入文件要慢得多。在您的设计中,您是否最小化文件打开调用?
答案 3 :(得分:0)
如果我理解正确,你想要写下你收到的无符号长整数的低位length
。您可以通过屏蔽所需的位来保存通过输入位的循环:
unsigned long long mask = (1ull << length) - 1; // creates a mask of 'length' 1's
BitBuffer = Data & mask;
作为评论,我不明白为什么你的测试和写作在第一个版本的循环中。
答案 4 :(得分:0)
首先,您需要编写代码以使其易于理解。我无法轻易理解您的任何代码片段。这是尝试重新格式化和重构第一个更简单,并添加一些注释:
/**
* @brief Write some bits to a file.
*
* The bits are written MSB-first to a temporary 64-bit integer, which is
* then written to the file in host byte-order.
*
* @param Data The data to write to the file. Only the least-significant
* Length bits are written. Of the bits that are written, the
* most significant bit is written first.
* @param Length The length of the data to write, in bits. Must be <= 64.
* @param OutFile The file to write to
*
* @note This function is not thread-safe
* @note This function stores some state in a static variable. You must
* ensure that the total data written is a multiple of 64 bits, or
* some data will be lost. You can only switch from one OutFile to
* another on a 64-bit boundry.
*/
void WriteBitsToFile(unsigned long long Data,
unsigned Length,
std::ofstream & OutFile)
{
static unsigned long long BitBuffer = 0;
static unsigned BitCounter = 0;
// Loop through input bits, one bit at a time
for (int i = (int)Length; i >= 0; --i)
{
// Get the input bit
unsigned long long NextBit = ((Data >> i) & 1);
// Add it to the temporary buffer
BitBuffer = ((BitBuffer << 1) | NextBit);
BitCounter++;
// If the temporary buffer is full, write it out
if (BitCounter == 64)
{
OutFile.write((char *) & BitBuffer, sizeof(BitBuffer));
BitCounter = 0;
}
}
}
现在我明白你要做什么......
你的第二个版本看起来好多了,因为你正在避免每位循环。既然你要求优化这个,我假设你有分析结果表明这很慢?而且我假设您通过此方式提供了大量数据?
一种可能的优化是写入更大的缓冲区(我建议至少4kB)。这意味着您不需要经常调用write()。调用write()可能会相对较慢。
答案 5 :(得分:0)
这是使用更大缓冲区的一种方法。 (在Pseudo-C#中)
const int wordSz= sizeof(unsigned long long)*8;
void WriteBitsToFile(unsigned long long Data, unsigned Length, std::ofstream & OutFile) {
static unsigned long long BitBuffer[BUFSZ+1] ={0};
static unsigned bitsSoFar = 0;
Data &= (1 << Length) - 1;
int index = bitsSoFar/wordSz;
int offset = bitsSoFar - (index*wordSz);
BitBuffer[index]|=Data<<offset;
int remainder = offset+length-wordSz;
if (remainder > 0)
{
index++;
BitBuffer[index]=Data>>(length-remainder);
}
bitsSoFar+=length;
if (bitsPacked > BUFSZ*wordSz)
{
OutFile.write((char*)BitBuffer, BUFSZ*sizeof(unsigned long long));
bitsSoFar-=BUFSZ*wordSz;
BitBuffer[0]=BitBuffer[BUFSZ];
}
}