random.SystemRandom().randint() inefficient

Michael F. Stemper michael.stemper at gmail.com
Wed Jul 27 09:19:35 EDT 2022


On 26/07/2022 16.47, Cecil Westerhof wrote:
> Chris Angelico <rosuav at gmail.com> writes:
> 
>> On Wed, 27 Jul 2022 at 06:06, Cecil Westerhof via Python-list
>> <python-list at python.org> wrote:
>>>
>>> Chris Angelico <rosuav at gmail.com> writes:
>>>
>>>> On Wed, 27 Jul 2022 at 01:06, Cecil Westerhof via Python-list
>>>> <python-list at python.org> wrote:
>>>>>
>>>>> I need to get a random integer. At first I tried it with:
>>>>>      from secrets import randbelow
>>>>>      index = randbelow(len(to_try))
>>>>>
>>>>> This works perfectly, but it took some time. So I thought I try:
>>>>>      from random  import SystemRandom
>>>>>      index = SystemRandom().randint(0, len(to_try) - 1)
>>>>>
>>>>> A first indication is that the second version would take about two
>>>>> times as much time as the first. Is there a reason for this, or should
>>>>> this not be happening?
>>>>>
>>>>
>>>> You're setting up a brand new SystemRandom instance just for a single
>>>> random number. For a fairer comparison, set up the instance, then
>>>> generate far more than just a single number, and see how that goes.
>>>
>>> Thanks. I thought I did something wrong and I did.
>>> I will try to implement like you said and look what the result will
>>> be. (And share it.)
>>
>> Thanks! Don't feel bad; performance testing is *hard*, getting
>> meaningful results takes a lot of of fiddling with parameters, and
>> getting interesting AND meaningful results can sometimes seem about
>> impossible.
>>
>>> (As I understand it both do more, or less the same and should have
>>> comparable performance.)
>>
>> In normal production work? Yes (the SystemRandom object doesn't have
>> any significant state - a seeded RNG could have a lot more overhead
>> here). But for performance testing? The work of instantiating the
>> class could be completely irrelevant, or it could be dominating your
>> results. It's hard to say, hence the suggestion to try it without
>> reinstantiating.
> 
> It had a very big influence. Original it took about three times more
> time to run my program. (The program was still running when I posted
> the original post and the difference was higher as I anticipated.)
> Removing that did cut about 45% of the execution time of the program.
> (So the initiation is quit expensive.)
> But it still takes about 50% more time. So I am still a bit
> flabbergasted.
> 
> The new code:
>      from random  import SystemRandom
>      system_random   = SystemRandom()
>      index = system_random.randint(0, len(to_try) - 1)

This is orthogonal to your question, but might be of some use to you:

The combination of using len(to_try) as an argument to randint() and
saving the output to a variable named "index" suggests that you might
be setting up to select a random element from to_try, as in:
   something = to_try[index]

If that is the case, you might want to consider using random.choice() instead:

   >>> from random import choice
   >>> to_try = [2,3,5,7,11,13,"seventeen",19]
   >>> choice(to_try)
   2
   >>> choice(to_try)
   'seventeen'
   >>> choice(to_try)
   13
   >>> choice(to_try)
   5
   >>>

-- 
Michael F. Stemper
This sentence no verb.


More information about the Python-list mailing list