Python の爆速 "in set" に julia で挑む
@kitadakyou さんの Pythonで"in list"から"in set"に変えただけで爆速になった件とその理由 というブログのコードを julia の Array で挑んだらどうなるかを試してみました。
まず、自分の python3 で、"in set" 実行した時の時間です。
>>> for _ in range(10): # 今回は実験のため、10回実行
... result = 0
... start_time = time.time()
... for _ in range(100000):
... num = randint(1, 10000000) # 改めて1 ~ 10000000 の間の数値をランダムに 100000 個選び、集合中にあれば result を + 1 する
... if num in a: # 要素が集合中に存在するかチェック
... result += 1
... # print(result)
... print("elapsed_time:{time} sec".format(time=time.time() - start_time))
...
elapsed_time:0.17500686645507812 sec
elapsed_time:0.17588305473327637 sec
elapsed_time:0.17502999305725098 sec
elapsed_time:0.1756739616394043 sec
elapsed_time:0.17586398124694824 sec
elapsed_time:0.17543387413024902 sec
elapsed_time:0.1754751205444336 sec
elapsed_time:0.17451786994934082 sec
elapsed_time:0.1747879981994629 sec
上記がベンチマークです。
では、julia に移植、といっても set() はないので、Array() で書きます。
julia> A = rand(1:10^5,10^5);
julia> for i in 1:10
result = 0
@time for i in 1:10^5
if rand(1:10^7) in A
result +=1
end
end
print(result)
end
4.826036 seconds (100.00 k allocations: 1.526 MiB)
644 6.101467 seconds (99.99 k allocations: 1.526 MiB)
633 5.478746 seconds (99.99 k allocations: 1.526 MiB)
598 6.400460 seconds (99.99 k allocations: 1.526 MiB)
672 5.073428 seconds (100.00 k allocations: 1.526 MiB)
617 5.145575 seconds (100.00 k allocations: 1.526 MiB)
609 5.333662 seconds (100.00 k allocations: 1.526 MiB)
649 5.370491 seconds (100.00 k allocations: 1.526 MiB)
623 5.060122 seconds (99.99 k allocations: 1.526 MiB)
650 5.429527 seconds (100.00 k allocations: 1.526 MiB)
644
ちょっと悲しいですが、python に10倍以上の差で負けています。
単純に関数化しても期待したよりも遥かに小さな変化です。
julia> function compair_a()
result = 0
for i in 1:10^5
if rand(1:10^7) in A
result +=1
end
end
print(result)
end
compair_a (generic function with 1 method)
julia> for i in 1:10
@time compair_a()
end
588 5.119351 seconds (100.00 k allocations: 1.526 MiB)
674 4.885485 seconds (100.00 k allocations: 1.526 MiB)
653 5.554557 seconds (100.00 k allocations: 1.526 MiB)
612 4.990193 seconds (100.00 k allocations: 1.526 MiB)
658 5.416396 seconds (100.00 k allocations: 1.526 MiB)
643 5.082678 seconds (100.00 k allocations: 1.526 MiB)
687 4.965522 seconds (100.00 k allocations: 1.526 MiB)
626 4.842607 seconds (99.99 k allocations: 1.526 MiB)
635 4.879983 seconds (100.00 k allocations: 1.526 MiB)
627 5.068559 seconds (100.00 k allocations: 1.526 MiB)
なら、map() を使ってみよう。
julia> function conpair_a1()
A1 = rand(1:10^7, 10^5)
B1 = map(x -> x in A, A1)
print(sum(B1))
end
conpair_a1 (generic function with 1 method)
julia> for i in 1:10
@time conpair_a1()
end
616 4.849527 seconds (126.83 k allocations: 3.727 MiB)
629 4.948732 seconds (100.00 k allocations: 2.384 MiB)
602 4.862076 seconds (100.01 k allocations: 2.384 MiB)
640 4.906242 seconds (100.00 k allocations: 2.384 MiB)
645 4.859775 seconds (100.01 k allocations: 2.384 MiB)
673 4.951097 seconds (100.00 k allocations: 2.384 MiB)
639 4.855138 seconds (100.00 k allocations: 2.384 MiB)
641 4.932278 seconds (100.00 k allocations: 2.384 MiB, 0.08% gc time)
649 4.852540 seconds (100.00 k allocations: 2.384 MiB)
637 4.958297 seconds (100.01 k allocations: 2.385 MiB)
メチャクチャ悔しいので、ともかく答えだけ早く出す方法に変更です。
julia> function intersect_a1()
A1 = rand(1:10^7, 10^5)
print(length(intersect(A1, A)))
end
intersect_a1 (generic function with 1 method)
julia> for i in 1:10
@time intersect_a1()
end
648 0.020620 seconds (41 allocations: 5.281 MiB)
636 0.025924 seconds (41 allocations: 5.281 MiB, 17.71% gc time)
645 0.014462 seconds (41 allocations: 5.281 MiB)
631 0.017685 seconds (41 allocations: 5.281 MiB)
637 0.020631 seconds (41 allocations: 5.281 MiB)
683 0.020915 seconds (41 allocations: 5.281 MiB)
622 0.024897 seconds (41 allocations: 5.281 MiB, 29.49% gc time)
656 0.017534 seconds (42 allocations: 5.281 MiB)
643 0.021651 seconds (41 allocations: 5.281 MiB)
695 0.024542 seconds (41 allocations: 5.281 MiB)
これなら楽勝ですが、根本的に行っている演算が異るので、ちょっと微妙な感じです。
普通に書くなら julia は for ループは python に比較して安定した速度が出るといわれています。最適化したコードなら python は苦手とされる for ループでもかなり早いですね。