选择与randint的表现

Sup*_*est 10 python random performance

我想在a和之间选择一个随机整数b.

我知道3种方法.但是,他们的表现似乎非常违反直觉:

import timeit

t1 = timeit.timeit("n=random.randint(0, 2)", setup="import random", number=100000)
t2 = timeit.timeit("n=random.choice([0, 1, 2])", setup="import random", number=100000)
t3 = timeit.timeit("n=random.choice(ar)", setup="import random; ar = [0, 1, 2]", number=100000)

[print(t) for t in [t1, t2, t3]]
Run Code Online (Sandbox Code Playgroud)

在我的机器上,这给出了:

0.29744589625620965
0.19716156798482648
0.17500512311108346
Run Code Online (Sandbox Code Playgroud)

使用在线翻译,这给出:

0.23830216699570883
0.16536146598809864
0.15081614299560897
Run Code Online (Sandbox Code Playgroud)

注意使用专用函数执行我正在做的事情的最直接版本(#1)比预先定义数组然后从中随机选择的最奇怪版本(#3)差50%.

这是怎么回事?

use*_*ica 6

这只是实施细节.randint委托给randrange,所以它有另一层函数调用开销,并randrange经历了很多参数检查和其他crud.相比之下,这choice是一个非常简单的单行.

以下是randint此调用的代码路径,其中删除了注释和未执行的代码:

def randint(self, a, b):
    return self.randrange(a, b+1)

def randrange(self, start, stop=None, step=1, _int=int, _maxwidth=1L<<BPF):
    istart = _int(start)
    if istart != start:
        # not executed
    if stop is None:
        # not executed

    istop = _int(stop)
    if istop != stop:
        # not executed
    width = istop - istart
    if step == 1 and width > 0:
        if width >= _maxwidth:
            # not executed
        return _int(istart + _int(self.random()*width))
Run Code Online (Sandbox Code Playgroud)

这里是代码路径choice:

def choice(self, seq):
    return seq[int(self.random() * len(seq))]
Run Code Online (Sandbox Code Playgroud)

  • 另请注意,对于两者而言,差异似乎是不变的.使用`range(10000)`而不是`[0,1,2]`和`randint(0,10000)`基本上和小例子一样.所以基本上你描述的开销只会让每个调用的`randint`比`choice`慢0.000012秒(假设你可以预定义你的选择集).这不是什么大问题.但是,应该避免使用`t2`,因为它也是创建列表的时间,因此大型列表会变慢. (2认同)