可以对比一下 choice 和 choices 的源码
https://hg.python.org/cpython/file/tip/Lib/random.py#l252https://hg.python.org/cpython/file/tip/Lib/random.py#l340choice 是生成一个随机的整数索引
choices 是把分布比重(默认等比重)转换成 0-1 的数轴,然后 random()生成 0-1 小数,对应到数轴上
大家底层都是用的 random(),choices 更复杂,理应更慢才对
使用 cProfile 测试
>>>
cProfile.run('"".join(random.choice(string.ascii_letters + string.digits) for _ in range(10**7))')
60321941 function calls in 21.869 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
10000001 5.516 0.000 20.772 0.000 <string>:1(<genexpr>)
1 0.000 0.000 21.869 21.869 <string>:1(<module>)
10000000 6.283 0.000 8.918 0.000
random.py:222(_randbelow)
10000000 5.381 0.000 15.256 0.000
random.py:252(choice)
1 0.000 0.000 21.869 21.869 {built-in method builtins.exec}
10000000 0.956 0.000 0.956 0.000 {built-in method builtins.len}
10000000 0.785 0.000 0.785 0.000 {method 'bit_length' of 'int' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
10321936 1.851 0.000 1.851 0.000 {method 'getrandbits' of '_random.Random' objects}
1 1.097 1.097 21.869 21.869 {method 'join' of 'str' objects}
>>>
cProfile.run('"".join(random.choices(string.ascii_letters + string.digits, k=10**7))')
10000007 function calls in 3.463 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.014 0.014 3.463 3.463 <string>:1(<module>)
1 0.000 0.000 3.374 3.374
random.py:340(choices)
1 2.780 2.780 3.374 3.374
random.py:352(<listcomp>)
1 0.000 0.000 3.463 3.463 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {built-in method builtins.len}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.075 0.075 0.075 0.075 {method 'join' of 'str' objects}
10000000 0.594 0.000 0.594 0.000 {method 'random' of '_random.Random' objects}
可以看到:
1. choice 法到底层用的是 getrandbits
# Only call self.getrandbits if the original random() builtin method
# has not been overridden or if a new getrandbits() was supplied.
说明 getrandbits 应该是比 random 更快的,否则官方不会这么用
2. choice 法的 function calls 是 choices 法的 6 倍,而正好时间也是将近 6 倍,很可能这两者是有关联的
3.看 tottime,choices 的时间主要是在
random.py:352return [population[_int(random() * total)] for i in range(k)]
这里构建 list 消耗大可以理解
choice 的时间主要是在<string>:1,
random.py:222,
random.py:252 上
choice 一个 5 行的函数,吃这么多时间,很难理解