簡體   English   中英

為什么這個 Julia 片段比等效的 Python 慢得多? (帶字典)

[英]Why is this Julia snippet so much slower than the Python equivalent? (with dictionaries)

我在 Python Jupyter 中有以下代碼:

n = 10**7
d = {}

%timeit for i in range(n): d[i] = i

%timeit for i in range(n): _ = d[i]

%timeit d[10]

以下時間:

763 ms ± 19.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
692 ms ± 3.74 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
39.5 ns ± 0.186 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

這在 Julia

using BenchmarkTools
d = Dict{Int64, Int64}()
n = 10^7
r = 1:n

@btime begin
    for i in r
        d[i] = i
    end
end
    
@btime begin
    for i in r
        _ = d[i]
    end
end

@btime d[10]

隨着時間:

  2.951 s (29999490 allocations: 610.34 MiB)
  3.327 s (39998979 allocations: 762.92 MiB)
  20.163 ns (0 allocations: 0 bytes)

我不太明白的是為什么 Julia 在循環中的字典值分配和檢索(前兩個測試)中似乎要慢得多,但同時在單鍵檢索中要快得多(最后一個測試)。 在循環中似乎慢了 4 倍,但如果不在循環中則快兩倍。 我是 Julia 的新手,所以我不確定我是否在做一些不理想的事情,或者這是否是預期的。

由於您在頂級 scope 中進行基准測試,因此您必須在@btime中使用$插入變量,因此對代碼進行基准測試的方法是:

julia> using BenchmarkTools

julia> d = Dict{Int64, Int64}()
Dict{Int64, Int64}()

julia> n = 10^7
10000000

julia> r = 1:n
1:10000000

julia> @btime begin
           for i in $r
               $d[i] = i
           end
       end
  842.891 ms (0 allocations: 0 bytes)

julia> @btime begin
           for i in $r
               _ = $d[i]
           end
       end
  618.808 ms (0 allocations: 0 bytes)

julia> @btime $d[10]
  6.300 ns (0 allocations: 0 bytes)
10

在 Jupyter Notebook 的同一台機器上 Python 3 的時序是:

n = int(10.0**7)
d = {}
%timeit for i in range(n): d[i] = i
913 ms ± 87.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit for i in range(n): _ = d[i]
816 ms ± 92.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit d[10]
50.2 ns ± 2.97 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

但是,對於第一個操作,我假設您更願意對此進行基准測試:

julia> function f(n)
           d = Dict{Int64, Int64}()
           for i in 1:n
               d[i] = i
           end
       end
f (generic function with 1 method)

julia> @btime f($n)
  1.069 s (72 allocations: 541.17 MiB)

反對這一點:

def f(n):
    d = {}
    for i in range(n):
        d[i] = i
%timeit f(n)
1.18 s ± 65.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

It should also be noted that using a specific value of n can be misleading as Julia and Python are not guaranteed to resize their collections at the same moments and to the same new sizes (in order to store a dictionary you normally allocate more memory than needed為了避免 hash 沖突,這里實際上測試n的特定值可能很重要)。

編輯

請注意,如果我將全局變量聲明為const all 很快,那么編譯器可以優化代碼(它知道綁定到全局變量的值的類型不能改變); 因此不需要使用$

julia> using BenchmarkTools

julia> const d = Dict{Int64, Int64}()
Dict{Int64, Int64}()

julia> const n = 10^7
10000000

julia> const r = 1:n
1:10000000

julia> @btime begin
           for i in r
               d[i] = i
           end
       end
  895.788 ms (0 allocations: 0 bytes)

julia> @btime begin
           for i in $r
               _ = $d[i]
           end
       end
  582.214 ms (0 allocations: 0 bytes)

julia> @btime $d[10]
  6.800 ns (0 allocations: 0 bytes)
10

如果你很好奇,這里有一個對線程的原生支持有什么好處是一個簡單的基准(這個功能是語言的一部分):

julia> Threads.nthreads()
4

julia> @btime begin
           Threads.@threads for i in $r
               _ = $d[i]
           end
       end
  215.461 ms (23 allocations: 2.17 KiB)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM