Pergunta

Estou executando este código para ver o impacto do desempenho do Biblioteca de criptografia Keyczar do Google:

from keyczar import keyczar, keys

def main(iters):
    key = keys.RsaPrivateKey.Generate()
    msg = "ciao"
    crypt = None
    for i in range(iters):
        print i, "\r",
        crypt = key.Encrypt(msg)
    for i in range(iters):
        print i, "\r",
        key.Decrypt(crypt)

if __name__ == '__main__':
    main(500)

Sob o Windows, 500 iterações levam cerca de 16 minutos. Sob uma partição do Ubuntu 9.04 na mesma máquina, 500 iterações levam cerca de 6 segundos.

Eu tentei criar um perfil (CProfile + Pstats), mas não tenho muita experiência em interpretar os resultados.

Alguém pode me dizer por que o mesmo código é executado mais de 150 vezes mais lentamente no Windows?


Editar 2010-01-16

Aqui está o meu script generate_key.py:

from keyczar import keyczar, keys

key = keys.RsaPrivateKey.Generate()

Aqui está minha linha de comando para criar um arquivo de estatísticas em generate_key:

C:\temp\python-keyczar-0.6b\tests\keyczar>python -m cProfile -o generate_key generate_key.py

Aqui está minha sessão Python para expandir os resultados:

>>> import pstats
>>> p = pstats.Stats('generate_key')
>>> p.strip_dirs().sort_stats(-1).print_stats(25)
Sat Jan 16 12:18:43 2010    generate_key

         83493 function calls (82974 primitive calls) in 5.131 CPU seconds

   Ordered by: standard name
   List reduced from 564 to 25 due to restriction <25>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
        1    0.000    0.000    0.210    0.210 AES.py:1(<module>)
        1    0.022    0.022    0.210    0.210 AES.py:1(__bootstrap__)
        1    0.000    0.000    0.000    0.000 DSA.py:115(DSAobj)
        1    0.001    0.001    0.005    0.005 DSA.py:14(<module>)
        1    0.000    0.000    0.000    0.000 DSA.py:174(DSAobj_c)
        1    0.000    0.000    0.000    0.000 DSA.py:26(error)
        1    0.000    0.000    0.001    0.001 RSA.py:125(size)
        1    0.000    0.000    0.000    0.000 RSA.py:13(<module>)
        1    0.000    0.000    0.000    0.000 RSA.py:140(publickey)
        1    0.000    0.000    0.000    0.000 RSA.py:146(RSAobj_c)
        1    0.000    0.000    0.000    0.000 RSA.py:23(error)
        1    0.000    0.000    4.816    4.816 RSA.py:26(generate)
        1    0.000    0.000    0.000    0.000 RSA.py:63(construct)
        1    0.000    0.000    0.000    0.000 RSA.py:85(RSAobj)
        1    0.003    0.003    0.004    0.004 SHA.py:4(<module>)
        1    0.000    0.000    0.000    0.000 __future__.py:48(<module>)
        1    0.000    0.000    0.000    0.000 __future__.py:74(_Feature)
        7    0.000    0.000    0.000    0.000 __future__.py:75(__init__)
        8    0.000    0.000    0.000    0.000 __init__.py:1(<module>)
        1    0.000    0.000    0.000    0.000 __init__.py:11(<module>)
        1    0.000    0.000    0.000    0.000 __init__.py:13(<module>)
        1    0.000    0.000    0.000    0.000 __init__.py:18(<module>)
        1    0.000    0.000    0.000    0.000 __init__.py:20(<module>)
        2    0.000    0.000    0.000    0.000 __init__.py:24(<module>)


<pstats.Stats instance at 0x023F5E40>
>>>

Portanto, o código do Windows é executado no Python. A maior parte do tempo de execução é gasta aqui:

def generate(bits, randfunc, progress_func=None):
    """generate(bits:int, randfunc:callable, progress_func:callable)

    Generate an RSA key of length 'bits', using 'randfunc' to get
    random data and 'progress_func', if present, to display
    the progress of the key generation.
    """
    obj=RSAobj()

    # Generate the prime factors of n
    if progress_func:
        progress_func('p,q\n')
    p = q = 1L
    while number.size(p*q) < bits:
        p = pubkey.getPrime(bits/2, randfunc)
        q = pubkey.getPrime(bits/2, randfunc)

    # p shall be smaller than q (for calc of u)
    if p > q:
        (p, q)=(q, p)
    obj.p = p
    obj.q = q

    if progress_func:
        progress_func('u\n')
    obj.u = pubkey.inverse(obj.p, obj.q)
    obj.n = obj.p*obj.q

    obj.e = 65537L
    if progress_func:
        progress_func('d\n')
    obj.d=pubkey.inverse(obj.e, (obj.p-1)*(obj.q-1))

    assert bits <= 1+obj.size(), "Generated key is too small"

    return obj

Estou executando pycrypto para baixo de aqui.

Foi útil?

Solução

O pycrypto possui um módulo C chamado _fastmath que usa o GNU MP para as operações de chave pública. Se não estiver disponível, ele usa os números inteiros longos nativos de Python, que são muito mais lentos.

Os dois arquivos são src/_fastmath.c e lib/cripto/publicKey/_slowmath.py

É provável que o Python no Windows não inclua GNU MP; portanto, no Windows, ele está usando _slowmath.py

Outras dicas

Para esse tipo de diferença, eu suspeitaria que o Linux está usando um módulo C para o trabalho. Talvez a versão do Windows não tenha instalado uma DLL em algum lugar, por isso está voltando ao código Python

Você está executando a mesma versão do Python nas duas plataformas?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top