2014-12-09 23 views
7

Sto cercando di creare stringhe alfa reali, intere, alfanumeriche, alfa e quindi scrivere in un file fino a quando le dimensioni del file raggiungono 10MB.Il modo più veloce per scrivere enormi dati nel file

Il codice è il seguente.

import string 
import random 
import time 
import sys 


class Generator(): 
    def __init__(self): 
     self.generate_alphabetical_strings() 
     self.generate_integers() 
     self.generate_alphanumeric() 
     self.generate_real_numbers() 

    def generate_alphabetical_strings(self): 
     return ''.join(random.choice(string.ascii_lowercase) for i in range(12)) 

    def generate_integers(self): 
     return ''.join(random.choice(string.digits) for i in range(12)) 

    def generate_alphanumeric(self): 
     return ''.join(random.choice(self.generate_alphabetical_strings() + 
            self.generate_integers()) for i in range(12)) 

    def _insert_dot(self, string, index): 
     return string[:index].__add__('.').__add__(string[index:]) 


    def generate_real_numbers(self): 
     rand_int_string = ''.join(random.choice(self.generate_integers()) for i in range(12)) 
     return self._insert_dot(rand_int_string, random.randint(0, 11)) 


from time import process_time 
import os 

a = Generator() 

t = process_time() 
inp = open("test.txt", "w") 
lt = 10 * 1000 * 1000 
count = 0 
while count <= lt: 
    inp.write(a.generate_alphanumeric()) 
    count += 39 
inp.close() 

elapsed_time = process_time() - t 
print(elapsed_time) 

Ci vogliono circa 225,953,125 mila secondo per completare. Come posso migliorare la velocità di questo programma? Si prega di fornire alcune informazioni sul codice?

+0

dove è il tempo trascorso nel tuo programma? – dm03514

+0

@MartijnPieters Ho provato lo stesso codice in Java e ci sono voluti ~ 0,93 secondi. – ajkumar25

+0

Il programma Java ha scritto sul disco. Ho controllato la dimensione del file manualmente dopo il completamento del processo. – ajkumar25

risposta

18

due ragioni principali per osservata "lentezza":

  • vostro ciclo while è lento, ha circa un milione di iterazioni.
  • Non si fa un uso corretto del buffering I/O. Non effettuare così tante chiamate di sistema. Attualmente, chiami lo write() circa un milione di volte.

Creare i dati in una struttura dati Python prima e chiamare write() solo volta.

questo è più veloce:

t0 = time.time() 
open("bla.txt", "wb").write(''.join(random.choice(string.ascii_lowercase) for i in xrange(10**7))) 
d = time.time() - t0 
print "duration: %.2f s." % d 

uscita: duration: 7.30 s.

Ora il programma passa gran parte del suo tempo generare i dati, vale a dire in random roba. Puoi facilmente vederlo sostituendo random.choice(string.ascii_lowercase) con ad es. "a". Quindi il tempo misurato scende al di sotto di un secondo sulla mia macchina.

E se si vuole avvicinarsi ancora di più a vedere quanto velocemente la macchina davvero è quando la scrittura su disco, utilizzare più veloce di Python modo per generare i dati abbastanza grande prima della scrittura su disco (?):

>>> t0=time.time(); chunk="a"*10**7; open("bla.txt", "wb").write(chunk); d=time.time()-t0; print "duration: %.2f s." % d 
duration: 0.02 s. 
+2

Cosa intendi con utilizzo corretto del buffer IO? – ajkumar25

+5

Stai scrivendo sul disco. Scrivere su disco è un processo fisico e logico complesso. Comporta un sacco di meccanica e controllo. È * molto * più veloce dire al disco "Qui, questo è 10 MB di dati, scrivilo!" che dirlo milioni di volte "Qui, questo è 1 byte di dati, scrivilo!".Pertanto, il sistema operativo ha un meccanismo per "raccogliere" i dati che un processo vuole scrivere sul disco prima di salvarlo sul disco. Tuttavia, se si dice esplicitamente al sistema operativo di scrivere piccole parti, allora lo fa. Lo stai facendo e questo è lento. Vedi la mia modifica. –

+0

@ Jan-PhilipGehrcke: esiste un modo per creare un file writer bufferizzato? –

2

Si creano letteralmente miliardi di oggetti che vengono quindi rapidamente eliminati. In questo caso, probabilmente è meglio scrivere le stringhe direttamente nel file invece di concatenarle con ''.join().

1

Il while loop under main calls generate_alphanumeric, che sceglie diversi caratteri di stringhe (create in modo casuale) composte da dodici lettere ascii e dodici numeri. Questo è fondamentalmente lo stesso della scelta casuale di una lettera casuale o di un numero casuale per dodici volte. Questo è il tuo principale collo di bottiglia. Questa versione renderà il tuo codice un ordine di grandezza più veloce:

def generate_alphanumeric(self): 
    res = '' 
    for i in range(12): 
     if random.randrange(2): 
      res += random.choice(string.ascii_lowercase) 
     else: 
      res += random.choice(string.digits) 
    return res 

Sono sicuro che può essere migliorato. Ti suggerisco di prendere il tuo profiler per un giro.

+0

No, questo non è il collo di bottiglia principale. Sono d'accordo che il suo modo di generare i dati non è ottimale, ma no no no, questo non è il collo di bottiglia di questo programma. Il suo collo di bottiglia è un I/O inefficiente. –

+0

Il tempo di esecuzione originale (sulla mia macchina) è 0m28.587s. La mia versione richiede 0m2.266s. Quale altro cambiamento vorresti che avesse un impatto maggiore? – debiatan

+0

Rimuovere il ciclo while, richiamare 'write()' solo una volta. –

Problemi correlati