Bash forやseqの遅延評価

1-6.パイプ・フィルタ


『剣風伝奇ベルセルク』(1997-1998)(TVアニメ第1作)
『ベルセルク』(2016)(TVアニメ第2作)
1作目と2作目がすごく離れているなあと気になり、1作目を見てみたらとても面白い。強い傭兵団がどんどん力をつけていく話で、ベルセルクの壮大な物語の中で黄金時代と呼ばれるストーリーで、次へ次へと視聴が進んでしまいました。これは漫画も見なければならないと、一巻から見たのですが・・・

むむっ。よくわからない。黄金時代って漫画の一巻じゃないの??? いや、一巻といいつつ、もっと前の巻があるのでは?と、しばらく呆然と本屋で立ち尽くしていました。結局wikiで調べて、黄金時代は3巻からとわかりました。まあ漫画は後にして2作目の『ベルセルク』の視聴を始めましたが、まるで別のアニメです。
黄金時代のように貪欲に次が見たいって面白さがないですが、醜い心の人物が醜く描かれていることに興味が湧いて、次はどんな醜い奴らが登場するのかってのを楽しみに視聴しています。

漫画の『ベルセルク』の1,2巻は、3巻よりも時間軸が後ろなのですが、linuxを使っていると順序を意識することがあります。本来は左から右へと処理されるパイプですが、実は右の処理に、左の処理が左右されることがあります。headとtailを使いながら、探っていきたいと思います。まずはseqコマンド単体の時間。headコマンドとtailコマンドでフィルタリングした時間を計測をしてみます。

seqの処理時間

takk~$ time seq 1000
1
2
3
4

省略

998
999
1000

real	0m0.011s
user	0m0.000s
sys	0m0.003s
takk~$

seq | head の処理時間(1)

takk~$ time seq 1000 | head
1
2
3
4
5
6
7
8
9
10

real	0m0.003s
user	0m0.004s
sys	0m0.000s
takk~$

seq | tail の処理時間(1)

takk~$ time seq 1000 | tail
991
992
993
994
995
996
997
998
999
1000

real	0m0.003s
user	0m0.000s
sys	0m0.000s
takk~$

seq 1000で1000行のテキストが生成されますが、headとtailに違いはほぼありませんね。

seq | head の処理時間(2)

次はseq 1000000で試してみます。

~$ time seq 1000000 | head
1
2
3
4
5
6
7
8
9
10

real	0m0.004s
user	0m0.000s
sys	0m0.000s
takk~$

seq | tail の処理時間(2)

takk~$ time seq 1000000 | tail
999991
999992
999993
999994
999995
999996
999997
999998
999999
1000000

real	0m0.018s
user	0m0.028s
sys	0m0.004s
takk~$

tailコマンドの方がheadよりも時間がかかりました。
tailは最後の行を表示するのですから当然の結果ですね。headの結果がtailよりも早くなるのは当然なのですが、何か変です。headの処理時間は、seqの数字を増やす前と比べあまり変わってません。

seq | head の処理時間(3)

もっとseqの出力行数を増やしてみましょう。

takk~$ time seq 1000000000 | head
1
2
3
4
5
6
7
8
9
10

real	0m0.004s
user	0m0.000s
sys	0m0.000s
takk~$

seq | tail の処理時間(3)

takk~$ time seq 1000000000 | tail
999999991
999999992
999999993
999999994
999999995
999999996
999999997
999999998
999999999
1000000000

real	0m11.691s
user	0m19.420s
sys	0m3.856s
takk~$

tailは11秒も時間がかかっているのに、やはりheadの時間は変化がありません。これはseqコマンドの処理が遅延評価されているからに他なりません。

seq | head の処理時間(4)

seqで指定する数を極端に大きくしてみましょう。

takk~$ time seq 999999999999999999999999999999999999 | head
1
2
3
4
5
6
7
8
9
10

real	0m0.002s
user	0m0.000s
sys	0m0.000s
takk~$

一瞬で処理が終わりました。

無限ループ | head の処理時間

それなら無限ループでも大丈夫でしょうか。無限の数列をheadしてみます。

takk~$ for((i=1;;i++)){ echo $i;} | head
1
2
3
4
5
6
7
8
9
10
takk~$

無限ループになるはずが、headにより繰り返しは10で止まりました。headで10行だけ表示することがわかっているので、ループを10回で止めているってことですね。
無限数列にさらにパイプをつなげて処理してみましょう。パイプの最後のheadが効いています。
seq-lazy-head-001

コメント

タイトルとURLをコピーしました