11
2017-10-01 02:39:57 +08:00
可以对比一下 choice 和 choices 的源码
https://hg.python.org/cpython/file/tip/Lib/random.py#l252
https://hg.python.org/cpython/file/tip/Lib/random.py#l340
choice 是生成一个随机的整数索引
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 :1()
1 0.000 0.000 21.869 21.869 :1()
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 :1()
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()
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:352
return [population[_int(random() * total)] for i in range(k)]
这里构建 list 消耗大可以理解
choice 的时间主要是在:1,random.py:222,random.py:252 上
choice 一个 5 行的函数,吃这么多时间,很难理解