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 ループでもかなり早いですね。

B! LINE