When using pythons random.shuffle
function, I noticed it went significantly faster to use sorted(l, key=lambda _: random.random())
than random.shuffle(l)
. As far as I understand, both ways produce completely random lists, so why does shuffle
take so much longer?
Below are the times using timeit
module.
from timeit import timeit
setup = 'import random\nl = list(range(1000))'
# 5.542 seconds
print(timeit('random.shuffle(l)', setup=setup, number=10000))
# 1.878 seconds
print(timeit('sorted(l, key=lambda _: random.random())', setup=setup, number=10000))
On CPython (the reference interpreter) random.shuffle
is implemented in Python (and implemented in terms of _randbelow
, itself a Python wrapper around getrandbits
, the C level function that ultimately implements it, and which can end up being called nearly twice as often as strictly necessary in an effort to ensure the outputs are unbiased); sorted
(and random.random
) are implemented in C. The overhead of performing work in Python is higher than performing similar work in C.
Why doesn't
random.shuffle
just return the list usingsorted
if it runs so much faster using C?@Evan: It's using a fairly painstaking algorithm that guarantees (to the limits of the PRNG) a perfect shuffle; avoiding bias is a surprisingly hard problem, and making it faster is less of a priority than making sure it's definitely correct. There have been a number of bugs in the
random
module that led to slight biases in output (it's why_randbelow
is implemented the way it is now), and they've generally been pretty gunshy about using faster algorithms that aren't provably unbiased.