我正在阅读此pull request on dablooms
最重要的是,Murmur不会在堆栈/寄存器上返回哈希值,而是将其直接写入提供的缓冲区。这使得使用大量随机数据填充bloom->哈希缓冲区非常容易,并逐步执行模块化。
for (i = 0; i < bloom->nsalts; i++, hashes += 4) {
MurmurHash3_x64_128(key, key_len, bloom->salts[i], hashes);
hashes[0] = hashes[0] % bloom->counts_per_func;
hashes[1] = hashes[1] % bloom->counts_per_func;
hashes[2] = hashes[2] % bloom->counts_per_func;
hashes[3] = hashes[3] % bloom->counts_per_func;
}
我最近注意到一些库(至少在C ++中,我的知识非常有限,因为我是一个新手)似乎不会返回值,而是期望一个输出参数,他们将在其上写入结果。我更习惯看到这样的事情:
Matrix leftOperand = { /* some values */ };
Matrix rightOperand = { /* some values */ };
Matrix result;
result = multiplyMatrices( leftOperand, rightOperand );
其中result
是return
的{{1}}值。但是在我最近的项目中学习使用OpenGL,GLEW和freeglut,我经常看到这样的调用:
multiplyMatrices
我理解它的作用,但我觉得这个符号很奇怪。但是我越来越常见,当我看到上述拉动请求的作者“赞扬”时,我认为可能有充分的理由这样做。
因此,在我寻求编写不那么糟糕和有臭味的代码的过程中,我想知道这是不是很好的做法。我认为它必须是出于性能原因,但我不清楚是否从堆栈中推送/弹出比直接写入给定的内存地址要慢。
我正在寻找一些关于使用单一方式而不是另一种方式的原因的指南。
答案 0 :(得分:1)
我们在C中采用一个简单的例子:
struct X
{
/* a lot of data */
};
struct X func1(/*args*/)
{
struct X result;
/* fill in result */
return result;
}
int func2(/*args*/, struct X *result)
{
if (result == NULL)
return -1;
/* fill in *result */
return 0;
}
/* in the code */
struct X x;
x = func1(/* args */);
func2(/* args */, &x);
func1
,在自己的堆栈框架上填写必要的数据,然后行x = func1(...)
将其复制到x
。 func2
获取指向x
的指针作为其参数并将其填入。
正如您在此处看到的,使用func1
有两个缺点:
x
设置为无效状态(对于所有结构可能不存在,例如矩阵),否则无法报告错误。在某些情况下,根本不可能出现错误,因此第1点可能不一定成立。然而,如果您的结构很大,则第2点是性能杀手。
现在用C ++来想象同样的东西,除了struct X
现在是class X
,里面有一个复制构造函数和一堆std::string
和std::list
等。使用func2
的性能提升变得更加重要,因为复制类X
的对象现在需要调用多个复制构造函数,深度复制所有内容,然后在func1
内破坏本地对象。 (使用C ++ 11,这样会更糟糕(与C中一样糟糕),因为可以移动对象。)
人们想要使用func1
的唯一原因是为了便于阅读和编写。例如,比较一下:
string fix(const string &s);
void print(const string &s);
string str;
print(fix(str));
vs this:
void fix(const string &s, string &res);
void print(const string &s);
string str;
string fixed;
fix(str, fixed);
print(fixed);
第一个显然更容易理解,而第二个更有效。请注意,在像C这样的语言中,相当于第一个代码可能会导致内存泄漏,因此甚至无法实现。
所以问题归结为你更关注这两者中的哪一个。如果你和一个Java人谈话,他们可能会告诉你“性能差异很小,你甚至都不会注意到它”。如果你和一个C人交谈,他们可能会告诉你“某些架构的性能差异可能很小,但这并不意味着你可以去做不必要的事情。”
在您提到的帖子中,程序员正在尝试提高库的性能。他正在改进的功能是“填充缓冲区”。这会将缓冲区作为参数传递: