BlankTar

about | blog | works | photo

友人に whileとdo-whileに速度の違いはあるのか? というような質問をされました。
考えたこともなかったので、ちょっと色々やってみました。

とりあえず書いてみたコードがこれ。
#include <stdio.h>

int main(){
	int i=0;

	while(i<1000000000){
		i++;
	}

	return 0;
}
これがwhile版。

#include <stdio.h>

int main(){
	int i=0;

	do{
		i++;
	}while(i<1000000000);

	return 0;
}
こっちがdo-while版。
どちらもほぼ同じで、10億回ループするだけのコードです。

で、GCCでアセンブリにしてみる。
$ gcc -O0 -S while.c
コマンドはこんな感じ。

まずはwhile版。
.file	"while.c"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	rsp, rbp
	.cfi_def_cfa_register 6
	movl	$0, -4(rbp)
	jmp	.L2
.L3:
	addl	$1, -4(rbp)
.L2:
	cmpl	$999999999, -4(rbp)
	jle	.L3
	movl	$0, eax
	popq	rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Gentoo 4.8.4 p1.5, pie-0.6.1) 4.8.4"
	.section	.note.GNU-stack,"",@progbits
ラベル2つも使うんですね。おもしろい。

で、do-while版がこちら。
.file	"do-while.c"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	rsp, rbp
	.cfi_def_cfa_register 6
	movl	$0, -4(rbp)
.L2:
	addl	$1, -4(rbp)
	cmpl	$999999999, -4(rbp)
	jle	.L2
	movl	$0, eax
	popq	rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Gentoo 4.8.4 p1.5, pie-0.6.1) 4.8.4"
	.section	.note.GNU-stack,"",@progbits
お、ラベルが少ない。
ぱっと見こちらの方がシンプルな仕上がりになっています。行数も少ないし。

なるほど、do-whileの方が速いんだね。・・・とは言い難いので、実測値。
timeコマンドのuserの値を5つ。
while [秒]do-while [秒]
1回目1.6031.601
2回目1.5971.609
3回目1.6111.597
4回目1.6081.597
5回目1.6061.604
平均1.6151.602

・・・うーん。

結論: whileとかdo-whileとかどっちでもいいから、効率的なアルゴリズムを考えなさい。
< python3.4を使うならpathlibを使おう uwsgiのemperorを他のバージョンのpythonで。 >