我是愚蠢还是 Julia 比 python 快得离谱?

Ma *_*boi 8 python arrays performance dictionary julia

我正在尝试用 Python 完成一项非常简单的任务,我已经在 J​​ulia 中完成了这项任务。它包括获取多个 3d 元素的数组,并创建该列表中唯一值的索引字典(请注意,该列表有 6,000,000 个元素长)。我已经在 J​​ulia 中完成了此操作,并且速度相当快(6 秒) - 这是代码:

function unique_ids(itr)
#create dictionnary where keys have type of whatever itr is 
 d = Dict{eltype(itr), Vector}()
#iterate through values in itr
 for (index,val) in enumerate(itr)
    #check if the dictionary 
   if haskey(d, val)
     push!(d[val],index)
   else
     #add value of itr if its not in v yet 
     d[val] = [index]
   end
 end
 return collect(values(d))
end
Run Code Online (Sandbox Code Playgroud)

到目前为止,一切都很好。然而,当我尝试在 Python 中执行此操作时,它似乎需要很长时间,以至于我什至无法告诉你需要多长时间。所以问题是,我在这里做了一些愚蠢的事情,还是这只是这两种语言之间差异的现实?这是我的 Python 代码,是 Julia 代码的翻译。

def unique_ids(row_list):
    d = {}
    for (index,val) in tqdm(enumerate(row_list)):
        if str(val) in d:
            d[str(val)].extend([index])
        else:
            d[str(val)] = [index]
    return list(d.values())
Run Code Online (Sandbox Code Playgroud)

请注意,我在 Python 中使用字符串作为字典的键,因为在 Python 中不可能将数组作为键。

Ahm*_*AEK 0

python 比较慢,只是没有作者想象的那么慢,用优化的代码来展示这一点:

语言 时间(秒)
python 3.11 4.6
cpython + Numba (Jit) 3.3
朱莉娅1.8.5 1.9

python 在此仅慢 2.5 倍,当 numba 混合时仅慢 1.5 倍,因此如果您需要最后一点性能,请使用 julia,但 python 在其他方面会获胜,例如编译为轻量级可执行文件或拥有更多用于通用非数值编程的库。

仅优化 python 代码:

import random
from collections import defaultdict

input_list_len = 6_000_000
rand_max = 100
row_list = []
for _ in range(input_list_len):
    row_list.append(tuple(random.randint(0,rand_max) for x in range(3)))

def unique_ids(row_list):
    d = defaultdict(list)
    for (index,val) in enumerate(row_list):
        d[val].append(index)

    return list(d.values())

import time
t1 = time.time()
output = unique_ids(row_list)
t2 = time.time()
print(f"total time = {t2-t1}")
Run Code Online (Sandbox Code Playgroud)

优化的 numba LLVM jit 代码

import random
import numba
from numba.typed.typedlist import List
from numba.typed.typeddict import Dict
import numba.types
input_list_len = 6_000_000
rand_max = 100

@numba.njit
def generate_list():
    row_list = List()
    for _ in range(input_list_len):
        a = random.randint(0,rand_max)
        b = random.randint(0,rand_max)
        c = random.randint(0,rand_max)
        row_list.append((a,b,c))
    return row_list

row_list = generate_list()

@numba.njit("ListType(ListType(int64))(ListType(UniTuple(int64,3)))")
def unique_ids(row_list):
    d = Dict()
    for (index,val) in enumerate(row_list):
        if val in d:
            d[val].append(index)
        else:
            a = List()
            a.append(index)
            d[val] = a

    return List(d.values())

import time
t1 = time.time()
output = unique_ids(row_list)
t2 = time.time()
print(f"total time = {t2-t1}")
Run Code Online (Sandbox Code Playgroud)

优化的朱莉娅代码

using Random
Random.seed!(3);

input_list_len = 6_000_000
rand_max = 100
data::Vector{Tuple{Int64,Int64,Int64}} = Vector{Tuple{Int64,Int64,Int64}}()
for _ in 1:input_list_len
    push!(data, Tuple{Int64,Int64,Int64}(rand(0:rand_max,3)))
end

function unique_ids(itr)
    #create dictionnary where keys have type of whatever itr is 
     d = Dict{eltype(itr), Vector{Int}}()
    #iterate through values in itr
     for (index,val) in enumerate(itr)
        #check if the dictionary 
       if haskey(d, val)
         push!(d[val],index);
       else
         #add value of itr if its not in v yet 
         d[val] = [index]
       end
     end
     return collect(values(d))
    end

@time unique_ids(data);
@time unique_ids(data);
Run Code Online (Sandbox Code Playgroud)

  • 语言不被解释或编译;*实现*是。CPython(每个人都认为是“Python”)将 Python 源代码编译为 Python 字节代码,然后由虚拟机解释。不过,还有其他 Python 实现:PyPy 也是 Python 的 JIT 编译器。 (4认同)
  • 或者使用 pypy,它也是 JIT (2认同)
  • ...也就是说,出于令人信服和实际的原因(库可用性是另一个原因),我个人经常选择使用 Python+C 而不是 Julia,但我绝不会声称该组合具有更好的性能;Julia 将易用性和性能完美地结合在一起。 (2认同)
  • 我认为是这样的。1.0 于 2018 年发布。此后我不知道有任何重大更改,这应该是一个保证。 (2认同)