for 循环中的 1 句话为什么写 8 次

2017-03-07 17:55:58 +08:00
 zhyoulun

PHP 源码中 hash 的计算函数如下,想知道为什么 for 循环中把 1 句话写 8 次。

static inline ulong zend_inline_hash_func(const char *arKey, uint nKeyLength)
{
	register ulong hash = 5381;

	/* variant with the hash unrolled eight times */
	for (; nKeyLength >= 8; nKeyLength -= 8) {
		hash = ((hash << 5) + hash) + *arKey++;
		hash = ((hash << 5) + hash) + *arKey++;
		hash = ((hash << 5) + hash) + *arKey++;
		hash = ((hash << 5) + hash) + *arKey++;
		hash = ((hash << 5) + hash) + *arKey++;
		hash = ((hash << 5) + hash) + *arKey++;
		hash = ((hash << 5) + hash) + *arKey++;
		hash = ((hash << 5) + hash) + *arKey++;
	}
	switch (nKeyLength) {
		case 7: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
		case 6: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
		case 5: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
		case 4: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
		case 3: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
		case 2: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
		case 1: hash = ((hash << 5) + hash) + *arKey++; break;
		case 0: break;
EMPTY_SWITCH_DEFAULT_CASE()
	}
	return hash;
}
3844 次点击
所在节点    C
23 条回复
cnlinjie
2017-03-07 18:01:45 +08:00
懒得写双循环吧。复制粘贴复制粘贴。~2333333
kaneg
2017-03-07 18:03:05 +08:00
为了最大可能性的提高性能,所以尽量减少循环语句。
按一般人的思路,这里应该写一个 8 次的循环,但写引擎的人会尽力压榨性能。
R18
2017-03-07 18:04:07 +08:00
跟 8bit 有关系吗?
rogerchen
2017-03-07 18:04:54 +08:00
两点
1. loop unrolling
2. 手动触发编译器向量化 heuristic

第一点是一定的,第二点是有可能的。
sujin190
2017-03-07 18:06:53 +08:00
其实是和 cpu 缓存有关,对齐缓存,提高效率
rogerchen
2017-03-07 18:08:23 +08:00
多说一点, unrolling 是很常见的优化技巧,而且是无视架构的,能够大幅缩减控制流中累加和尾后测试的开销,特别是循环体比较简单的时候优化系数很高。

Ref: https://en.wikipedia.org/wiki/Loop_unrolling
zhyoulun
2017-03-07 18:28:06 +08:00
@rogerchen 看了下 loop unrolling ,很靠谱
zhyoulun
2017-03-07 18:29:32 +08:00
@rogerchen 注意到程序的注释中也写到了这是 unrolled 过的变体, variant with the hash unrolled eight times
cute
2017-03-07 18:33:32 +08:00
undeflife
2017-03-07 18:36:22 +08:00
不懂 php 但是 c 的循环展开是可以由编译器完成的
phrack
2017-03-07 18:51:29 +08:00
觉得是不必要的手动优化。

写一个循环,编译器检查到这样的循环会自动展开的。
Yourshell
2017-03-07 19:19:07 +08:00
好像 Duff's device
xavierskip
2017-03-07 19:23:14 +08:00
不懂,不过最近听别人抱怨写 swift ,某些语句拆开写能大幅度缩短编译时间。
Shura
2017-03-07 19:48:52 +08:00
csapp 中好像提到过这种优化方式,远古时候能够加速循环,现在的编译器已经能自动进行这种优化了。
roychan
2017-03-07 20:03:40 +08:00
现在编译器也能 unroll 了吧。。。
Quaintjade
2017-03-07 20:16:12 +08:00
我只知道 VBA 里 a^n 写开成 a*a*a*...*a 能大幅提高效率
Contextualist
2017-03-07 20:25:01 +08:00
这是 loop unrolling 中的 Duff's device 的抽离出 switch 的写法,而原版 Duff's device 是对于 C 语言中 switch 最精妙的利用 (误用,把 switch 当 goto 用
https://zh.wikipedia.org/wiki/达夫设备
zhidian
2017-03-07 20:27:56 +08:00
OpenMP 示例代码里也有看到用 loop unrolling 把不可并行的循环变得可以并行。
bigpigeon
2017-03-07 20:47:11 +08:00
@xavierskip 可能要考虑历史因素和环境因素把,可能那个年代 c 编译器没这种优化,可能某些 cpu 架构下的 c 编译器没做这种优化
IgniteWhite
2017-03-07 22:59:58 +08:00
为啥都要像汇编一样考虑循环展开。。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/345648

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX