2010-11-27 5 views
3

Dans le code ci-dessous, la concaténation est le goulot d'étranglement. Comme vous pouvez le voir j'ai essayé quelques méthodes sophistiquées pour accélérer cela, mais c'est sanglant lent de toute façon. Je voudrais savoir s'il y a quelque chose que je peux faire pour le faire connaître.Comment accélérer la concaténation de chaînes en Python?

BTW à la fois simple et secret sont données lues à partir du fichier binaire et ils sont assez grand (environ 1MB)

x = b'' 
if len(plain) < len(secret*8): 
    return False 
i = 0 

for secByte in secret: 
    for j in range(8): 
     z = setBit(plain[i],0,getBit(secByte,j)) 
     #x += bytes([z]) 
     x = x.join([b"", bytes([z])]) 
     #x = array.array("B",(int(z) for z in x.join([b"", bytes([z])]))).tostring() 
     i = i+1 
+0

pouvez-vous ajouter un simple « C » comme pseudocode de ce que vous essayez? Je ne suis pas familier avec setBit en Python ... –

+0

Pour les méthodes de concaténation de chaînes et la vitesse, voir ceux-ci: http: //stackoverflow.com/questions/1316887/what-is-the-most-efficient-string-concatenation-method-in- python – mshsayem

+0

. . . http://stackoverflow.com/questions/1349311/python-string-join-is-faster-than-but-whats-wrong-here – mshsayem

Répondre

5

Je ne pense pas que vous devriez utiliser la concaténation de chaîne du tout pour cela. Il serait préférable de créer un bytearray mutable de la taille complète des données finales, puis de définir chaque octet. Ceci est très O (N) et pour ce que vous faites en utilisant un bytearray est beaucoup plus naturel que la manipulation de chaînes:

x = bytearray(len(secret)*8) # creates an array of zero bytes 
i = 0 
for secByte in secret: 
    for j in range(8): 
     x[i] = setBit(plain[i], 0, getBit(secByte, j)) 
     i += 1 
+0

tyvm, c'est exactement ce dont j'avais besoin (cela fonctionne comme 100x plus rapide) xscott solution est propably aussi vite que cela, mais celui-ci est un peu mieux adapté à mon problème – sowa

7

listes Python ont O (1) append, au moins au sens amorti. Au lieu de faire la jointure dans la liste la plus interne, vous pouvez construire une grande liste et ensuite les rejoindre à la fin. Cela va transformer votre algorithme de O (N^2) à O (N). Il est difficile de vous donner le code de travail sans savoir exactement ce que vos fonctions SETBIT() et getBit() font, mais quelque chose comme:

L = [] 
for secByte in secret: 
    for j in range(8): 
     z = ... 
     L.append(z) 
x = b"".join(L) 
+1

Cela n'a pas été vrai depuis Python 2.3. Heure du code avec concaténation et avec des jointures. –

+3

@nate c, les chaînes Python sont un tableau d'octets contigus et de longueur associée. Son code avec x.join (...) crée une nouvelle chaîne légèrement plus longue à chaque fois avant de libérer l'ancienne chaîne quand il l'affecte. C'est le comportement O (N^2). Vous avez tort, et vous ne devriez pas m'avoir modulé. – xscott

+2

La suggestion que l'on construit des chaînes comme des listes et ne les joignent que si nécessaire (de préférence après la construction de la liste entière) est toujours valide pour autant que je sache. C'est une pratique Python recommandée depuis très longtemps. –