map_between を計測してみる
こんにちわ。こんにちわ。今日は ついったー とかいう いんたーねっつ をしていたら危うく童貞認定されるという濡れ衣を着せられて動揺を隠す事を禁じ得ない tell-k です。
さてタイトルの話ですが昨日の記事で、map_between という関数を、いくつか書いた + id:imagawa_yakata さんが書いてくれたヤツがあったので、パフォーマンス的にはどれが良いのかというを計測してみようとおもいます。というのもあまり普段ベンチマークとかとらないなぁ、ちゃんとしなきゃなぁと思ったのでやってみた次第です。
計測対象
昨日までに自分が思いついたのも含めて、4つの下記関数を計測しようと思います。
#!/usr/bin/env python #-*- coding:utf8 -*- from itertools import imap def map_between1(x, func): return list(imap(func, x, x[1:])) def map_between2(lst, func): itr = iter(lst) x = itr.next() for y in itr: yield func(x, y) x = y def map_between3(lst, func): return [func(lst[i], lst[i + 1]) for i in range(len(lst) - 1)] def map_between4(lst, func): return (func(lst[i], lst[i + 1]) for i in range(len(lst) - 1))
Benchmakerで速度を計測
各関数の計測をするにあたって、Benchmakerモジュールというのがよさげだったのでこれを利用します。
計測のコードはこんな風にしました。Benchmakerいいですね。withをサポートしてて、withブロックで
囲むだけで計測対象になるので楽ですね。
test = range(10000000) func = lambda x, y: x + y with Benchmarker() as bm: with bm('map_between1'): ret = map_between1(test, func) with bm('map_between2'): ret = list(map_between2(test, func)) with bm('map_between3'): ret = map_between3(test, func) with bm('map_between4'): ret = list(map_between4(test, func))
計測をするにあたっての留意点です。
- 最終的に結果として欲しいのはリスト型とします。
- map_between2 と map_between4 はジェネレータを返すので、list関数でキャストしています。
- 最初に渡すリストは結果の差異がわかりやすいように巨大にしています。
このコードを実行すると、下記のような結果になります。
## benchmarker: release 3.0.1 (for python) ## python platform: darwin [GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] ## python version: 2.7.2 ## python executable: /Users/tell_k/.virtualenvs/snippets/bin/python ## user sys total real map_between1 1.9100 0.1400 2.0500 2.0504 map_between2 3.1900 0.1300 3.3200 3.3222 map_between3 3.9600 0.1900 4.1500 4.1502 map_between4 4.5600 0.1800 4.7400 4.7400 ## Ranking real map_between1 2.0504 (100.0%) ************************* map_between2 3.3222 ( 61.7%) *************** map_between3 4.1502 ( 49.4%) ************ map_between4 4.7400 ( 43.3%) *********** ## Ratio Matrix real [01] [02] [03] [04] [01] map_between1 2.0504 100.0% 162.0% 202.4% 231.2% [02] map_between2 3.3222 61.7% 100.0% 124.9% 142.7% [03] map_between3 4.1502 49.4% 80.0% 100.0% 114.2% [04] map_between4 4.7400 43.3% 70.1% 87.6% 100.0%
map_betweenが 1番速かったようです。3と4はやっぱrangeで作り直してるだけあってダメダメでしたね。
条件を変えて速度を計測
さて上のヤツでは 2 と 4 はせっかくジェネレータが返ってくるのをわざわざリストにキャストしてもったいないですね。
- 結果はリストでなくても良い
と条件を変更したら、どれだけ変わるんでしょうねというのを計ってみました。コードではlist関数を除去しました。
test = range(10000000) func = lambda x, y: x + y with Benchmarker() as bm: with bm('map_between1'): ret = map_between1(test, func) with bm('map_between2'): ret = map_between2(test, func) with bm('map_between3'): ret = map_between3(test, func) with bm('map_between4'): ret = map_between4(test, func)
結果はこんな感じ。
## user sys total real map_between1 1.9100 0.1300 2.0400 2.0468 map_between2 0.0700 0.0100 0.0800 0.0856 map_between3 3.8800 0.1700 4.0500 4.0492 map_between4 0.1900 0.0300 0.2200 0.2199 ## Ranking real map_between2 0.0856 (100.0%) ************************* map_between4 0.2199 ( 38.9%) ********** map_between1 2.0468 ( 4.2%) * map_between3 4.0492 ( 2.1%) * ## Ratio Matrix real [01] [02] [03] [04] [01] map_between2 0.0856 100.0% 256.7% 2389.9% 4727.9% [02] map_between4 0.2199 38.9% 100.0% 930.9% 1841.5% [03] map_between1 2.0468 4.2% 10.7% 100.0% 197.8% [04] map_between3 4.0492 2.1% 5.4% 50.5% 100.0%
おぉ 2 が1番に躍り出ました!実質的に処理が実行されていないので、当然の結果ですけど。ジェネレータいいですね。
物言い
- 審判員 「ちょっとまった」
- 行司 「え?なに?」
- 審判員 「map_between1 は imapからの戻り値である imapオブジェクトを listでキャストしてるじゃないか。求める結果がリストでなくてもいいならiterableなオブジェクトのimapオブジェクトを返して計測しなきゃ公平とは言えんだろう?八百長かおい?」
- 行司 「はぁ。。そうですか。。。(八百長て)」
という感じで物言いがついたので map_between1 は imapの戻り値をlist型にキャストしていたので、そのままimapオブジェクトを返すようにして計測しなおしました。
def map_between1(x, func): return imap(func, x, x[1:])
以下が結果です。
## benchmarker: release 3.0.1 (for python) ## python platform: darwin [GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] ## python version: 2.7.2 ## python executable: /Users/tell_k/.virtualenvs/snippets/bin/python ## user sys total real map_between1 0.0700 0.0200 0.0900 0.0896 map_between2 0.0500 0.0100 0.0600 0.0562 map_between3 4.1200 0.2100 4.3300 4.3233 map_between4 0.1900 0.0400 0.2300 0.2217 ## Ranking real map_between2 0.0562 (100.0%) ************************* map_between1 0.0896 ( 62.7%) **************** map_between4 0.2217 ( 25.4%) ****** map_between3 4.3233 ( 1.3%) ## Ratio Matrix real [01] [02] [03] [04] [01] map_between2 0.0562 100.0% 159.4% 394.4% 7692.1% [02] map_between1 0.0896 62.7% 100.0% 247.4% 4825.4% [03] map_between4 0.2217 25.4% 40.4% 100.0% 1950.2% [04] map_between3 4.3233 1.3% 2.1% 5.1% 100.0%
結果はこんな感じでした。list型にキャストしなければimapもいい感じで速度は出るようですね。
- 行司「満足した?」
- 審判員「ち」
- 行司 「(ちってなんだよ。ちって。)」