Paulo Henrique Rodrigues Pinheiro

Um blog sobre programação para programadores!


Quantos números aleatórios posso gerar em 1 segundo?

Como trabalhar por um tempo determinado em Python é a resposta desse texto.

Dilbert - números aleatórios

Vi uma pergunta no grupo Python Brasil do Facebook, e o pessoal não tava muito amigável, então resolvi tentar responder.

Eis a pergunta:

Quantos números aleatórios um computador comum é capaz de gerar por segundo ?

A primeira coisa, vamos tentar tentando:


$ time (echo -e "import random\nfor i in range(100):\n  a=random.randrange(100)\n" | python -)

real    0m0.023s
user    0m0.018s
sys 0m0.006s

Agora é só ~~chutar~~ encontrar o número certo e tenho a resposta:


$ time (echo -e "import random\nfor i in range(1000):\n  a=random.randrange(100)\n" | python -)

real    0m0.025s
user    0m0.019s
sys 0m0.006s
$ time (echo -e "import random\nfor i in range(10000):\n  a=random.randrange(100)\n" | python -)

real    0m0.038s
user    0m0.032s
sys 0m0.006s
$ time (echo -e "import random\nfor i in range(100000):\n  a=random.randrange(100)\n" | python -)

real    0m0.155s
user    0m0.148s
sys 0m0.008s
$ time (echo -e "import random\nfor i in range(1000000):\n  a=random.randrange(100)\n" | python -)

real    0m1.264s
user    0m1.242s
sys 0m0.023s
$ time (echo -e "import random\nfor i in range(500000):\n  a=random.randrange(100)\n" | python -)

real    0m0.660s
user    0m0.643s
sys 0m0.018s
$ time (echo -e "import random\nfor i in range(600000):\n  a=random.randrange(100)\n" | python -)

real    0m0.792s
user    0m0.775s
sys 0m0.018s
$ time (echo -e "import random\nfor i in range(700000):\n  a=random.randrange(100)\n" | python -)

real    0m0.911s
user    0m0.889s
sys 0m0.023s
$ time (echo -e "import random\nfor i in range(800000):\n  a=random.randrange(100)\n" | python -)

real    0m1.045s
user    0m1.027s
sys 0m0.018s
$ time (echo -e "import random\nfor i in range(750000):\n  a=random.randrange(100)\n" | python -)

real    0m0.996s
user    0m0.975s
sys 0m0.022s
$ time (echo -e "import random\nfor i in range(770000):\n  a=random.randrange(100)\n" | python -)

real    0m1.005s
user    0m0.977s
sys 0m0.030s
$ time (echo -e "import random\nfor i in range(760000):\n  a=random.randrange(100)\n" | python -)

real    0m0.989s
user    0m0.970s
sys 0m0.019s
$ time (echo -e "import random\nfor i in range(765000):\n  a=random.randrange(100)\n" | python -)

real    0m0.995s
user    0m0.979s
sys 0m0.016s
$ time (echo -e "import random\nfor i in range(768000):\n  a=random.randrange(100)\n" | python -)

real    0m1.006s
user    0m0.983s
sys 0m0.023s
$ time (echo -e "import random\nfor i in range(767000):\n  a=random.randrange(100)\n" | python -)

real    0m0.997s
user    0m0.973s
sys 0m0.024s
$ time (echo -e "import random\nfor i in range(767500):\n  a=random.randrange(100)\n" | python -)

real    0m0.993s
user    0m0.976s
sys 0m0.018s
$ time (echo -e "import random\nfor i in range(767900):\n  a=random.randrange(100)\n" | python -)

real    0m1.007s
user    0m0.987s
sys 0m0.021s
$ time (echo -e "import random\nfor i in range(767800):\n  a=random.randrange(100)\n" | python -)

real    0m0.993s
user    0m0.979s
sys 0m0.014s
$ time (echo -e "import random\nfor i in range(767850):\n  a=random.randrange(100)\n" | python -)

real    0m1.000s
user    0m0.980s
sys 0m0.019s

Encontrei um número! Mas como responder com tamanha gambiarra, a uma pergunta num fórum de programação tão supimpa?

Então pensei em timeit. Esquece, não vem ao caso. Aí lembrei que o Unix tem interrupções de tempo. Nunca tinha usado, mas uma rápida pesquisa por 'python signal alarm' me deu isso:

17.4. signal — Set handlers for asynchronous events

Adaptei o exemplo no final da página e saiu esse código:

<script src="https://gist.github.com/paulohrpinheiro/a28af1fcf4bcdb6828da.js"></script>

O que esse código faz é definir uma função que será chamada quando o tempo determinado acabar (1 segundo). Ao ser chamada, essa função gera uma exceção e o while acaba, nos permitindo imprimir o contador.

Testei com vários Pythons, e obtive esses resultados:


$ python r.py
('Acabando....', 14)
785166
$ python3 r.py
Acabando.... 14
426140
$ pypy r.py
('Acabando....', 14)
23514193
$ pypy3 r.py
Acabando.... 14
3510197

Detalhe para como as versões 2 são mais rápidas que as 3. Eu não gosto de Python2, eisso me deixou um pouco decepcionado.

E atentem para o detalhe de como o print se comporta, nas diferentes versões...

Até que tá bom, já que na busca manual (usando python2) achei 767850 e no programa achei 785166. O importante é a ordem de grandeza ;).

É possível melhorar muito esse programa, por exemplo, tornando-o paralelo. Mas isso fica como desafio, e talvez, para um outro post.

Ah, o Unix e suas belezas: signal — simplified software signal facilities

Ah, o Python e suas belezas: 9.6. random — Generate pseudo-random numbers