Python'da ikame şifreleme kodu optimizasyonu
İşte benim kodum, 2000 rastgele anahtarla 500'e kadar rastgele uzunluktaki 2000 dizide basit ikame şifreleme gerçekleştiren üç farklı işlevi test etmek için.
Çıktı, en iyi işlevin o encrypt3zaman encrypt1ve en yavaş işlevin olduğunu gösterir encrypt2.
Daha da hızlı olan ikameyi gerçekleştirmek için başka yöntemler nelerdir encrypt3?
İkame, büyük harfli "A" ila "Z" alfabesi üzerinde gerçekleştirilir, başka hiçbir karaktere izin verilmez ve giriş dizilerinin yalnızca bu karakterleri içerip içermediği konusunda test gerekmez.
Kodun sonunda, tüm fonksiyonların aynı çıktıları üretip üretmediği test edilir.
from random import randrange, seed, sample
from time import perf_counter
alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def encrypt1(t,key):
v=dict(zip(alphabet,key))
return ''.join(v.get(n) for n in t)
def encrypt2(t,key):
return ''.join(key[alphabet.index(n)] for n in t)
def encrypt3(t,key):
return t.translate(str.maketrans(alphabet,key))
d=2000 # number of strings and keys to test
length=500 # biggest length of strings
strings=[''.join(chr(randrange(26)+65) for n in range(1,randrange(1,length))) for n in range(d)]
keys=[''.join(chr(n+65) for n in sample(range(26), 26)) for n in range(d)]
a=perf_counter()
en1=[encrypt1(strings[n],keys[n]) for n in range(d)]
b=perf_counter()
print('encrypt1 time:',b-a)
a=perf_counter()
en2=[encrypt2(strings[n],keys[n]) for n in range(d)]
b=perf_counter()
print('encrypt2 time:',b-a)
a=perf_counter()
en3=[encrypt3(strings[n],keys[n]) for n in range(d)]
b=perf_counter()
print('encrypt3 time:',b-a)
print("All encryptions outputs are same:",en1==en2==en3)
Çıktı:
# encrypt1 time: 0.09787979999999999
# encrypt2 time: 0.16948359999999996
# encrypt3 time: 0.029016399999999998
# All encryptions outputs are same: True
Yanıtlar
Herhangi bir işlem olmadan bir birleştirmenin aldığı süreyi basitçe karşılaştırarak, join translante/maketranskullanan ve uygulamadan daha hızlı bir çözüme sahip olmanın imkansız olduğunu hızlı bir şekilde görebilirsiniz translante/maketrans(uygulama için sondaki koda bakın).
Encryption join only took: 0.006335399999999991s
Encryption translation function took: 0.004516500000000034s
Ve dizelerin Python'da değişmez olduğunu ve birleştirmenin karakterleri birleştirmenin en hızlı (en hızlı değilse) saf python yollarından biri olduğunu bildiğimizde, daha iyi bir python uygulaması bulmak zor görünecektir.
Bununla birlikte, frank-yellin'in bahsettiği gibi, kodun daha hızlı çalışmasını sağlamak için bir C uygulaması yapılabilir. C kodu, bu durumda olduğu gibi düşük seviyeli işlemler için python'dan daha hızlı çalışır (bir dizedeki karakterin değiştirilmesi).
Bir C sürümü yazmayı denemek için, bir uzantının tüm standart metnini kendi başınıza yazmaktan çok daha kolay hale getirecek olan cython'u kullanabilirsiniz.
Örnek: pip install cythoncython: kurmanız python setup.py build_ext --inplaceve aşağıdaki 3 dosyayı içeren klasörde bozarak cython kodunu derlemeniz gerekecek
# file cencrypt.pyx
# distutils: language = c++
from libcpp.string cimport string
cdef char char_A = 'A'
def encrypt(t, key):
cdef string key_str = key.encode('UTF-8')
cdef string result = t.encode('UTF-8')
for i in range(len(result)):
result[i] = key_str[result[i]-char_A]
return result.decode('UTF-8')
# file main.py
from random import randrange, seed, sample
from time import perf_counter
from cencrypt import encrypt as encrypt_c
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def encrypt_join_only(t, key):
return ''.join(t)
def encrypt_dict(t, key):
v = dict(zip(alphabet, key))
return ''.join(v.get(n) for n in t)
def encrypt_array(t, key):
ord_a = ord("A")
return ''.join(key[n - ord_a] for n in map(ord, t))
def encrypt_translation(t, key):
return t.translate(str.maketrans(alphabet, key))
d = 2000 # number of strings and keys to test
length = 500 # biggest length of strings
strings = [''.join(chr(randrange(26) + 65) for n in range(1, randrange(1, length))) for n in range(d)]
keys = [''.join(chr(n + 65) for n in sample(range(26), 26)) for n in range(d)]
def measure_perf(function, name):
start = perf_counter()
result = [function(strings[n], keys[n]) for n in range(d)]
end = perf_counter()
print(f'Encryption {name} took: {end - start}s', )
return result
measure_perf(encrypt_join_only, "join only")
equal = (
measure_perf(encrypt_dict, "dict lookup") ==
measure_perf(encrypt_array, "array lookup") ==
measure_perf(encrypt_translation, "translation function") ==
measure_perf(encrypt_c, "cython implementation")
)
print("All encryptions outputs are same:", equal)
#file setup.py
from setuptools import setup
from Cython.Build import cythonize
setup(
ext_modules=cythonize("cencrypt.pyx")
)
Sonuçlar I7:
Encryption join only took: 0.006335399999999991s
Encryption dict lookup took: 0.044010700000000014s
Encryption array lookup took: 0.0479598s
Encryption translation function took: 0.004516500000000034s
Encryption cython implementation took: 0.002248700000000048s
All encryptions outputs are same: True