Quantos números aleatórios posso gerar em 1 segundo?
Como trabalhar por um tempo determinado em Python é a resposta desse texto.
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