3

I need to generate a huge amount of pseudo random integers in python 3.x .
Because of this I have to find the fastest way possible to do so.

Currently I'm using the python random library.

I found a similar answer using numpy at Fastest Way to generate 1,000,000+ random numbers in python but numpy isn't a standard library and i don't want to add 3rd party libraries (if not really needed) because I can't be sure that the guys I'm giving it to have them installed.

Actual code

def randInt(self, size=20, amount=1000):
    retVal = list()
    for i in range(0, amount):
        retVal.append(random.Random._randbelow(size)+1) #+1 to exclude 0 and include size
    return retVal

Tested with:

start = time.time()
test = randInt(size=100, amount=1000000)
stop = time.time()
print(stop-start)

These random functions I've tested:

_randbelow : 1.6700019 sec
randrange : 2.8700041 sec
randint : 3.1200051 sec

So my question is:
Is there any faster way than _randbelow using python 3.x default libraries?

Thanks
chill0r

Edit

Inbar Roses suggestion tested with same method (to compare results)

uniform : 0.9200019 sec
uniform parsed to int : 1.24000 sec

1.24 sec for 1 million integers should do it for me. If it should make problems later I probably have to look into multithreading or really using numpy.

Community
  • 1
  • 1
chill0r
  • 1,127
  • 2
  • 10
  • 26

3 Answers3

4

I have timed some random functions for you:

>>> import timeit
>>> timeit.Timer('random.randint(0,10)', 'import random').repeat()
[2.4119170746830494, 2.3879981728693105, 2.3901411990453427]
>>> timeit.Timer('random.randrange(0,10)', 'import random').repeat()
[2.274937673930552, 2.178254943434162, 2.1761346646683215]
>>> timeit.Timer('r._randbelow(10)', 'import random; r = random.Random()').repeat()
[1.115751664321607, 1.0852712353494667, 1.0842890608805078]
>>> timeit.Timer('random.uniform(0,10)', 'import random').repeat()
[0.5058132474312629, 0.4609362760654676, 0.4719052973948692]

Looks like uniform is your best shot.

Inbar Rose
  • 41,843
  • 24
  • 85
  • 131
2

Are you actually unsatisfied with getting 10^6 random numbers in 1-3 seconds? Any way of getting a pseudo-random number sequence depends on an algorithm that produces it. E.g. try reading from Linux's /dev/random, which is considered a 'real random' - it'll take weeks, maybe years to produce million random ints. On the other hand /dev/urandom - gives a pseudo-random bytes sequence which is considered random enough to be used in cryptography. It'll produce a million ints in a blink of an eye.

So, bottomline - if you are not satisfied with a speed of a random generator, you can look for a faster one, but in most cases the speed will be due to reduced complexity and a smaller amount of operations.

Zaur Nasibov
  • 22,280
  • 12
  • 56
  • 83
1

os.urandom() is usually faster:

int.from_bytes(os.urandom(5), byteorder='big')

To get similar functionality to _randbelow, you can mod the resulting number, first making sure 5 is big enough:

def randbelow(n):
    int.from_bytes(os.urandom(math.log2(n)//4+1), byteorder='big')%n
simonzack
  • 19,729
  • 13
  • 73
  • 118