Usa Python, dovrei memorizzare nella cache di grandi dati in array e scrivere per archiviare una volta?

StackOverflow https://stackoverflow.com/questions/19839646

  •  28-07-2022
  •  | 
  •  

Domanda

Ho sempre un download di crawler alimentato a gevent. Il crawler adotta il modello di consumatore del produttore, che alimenta la coda con dati come questo {metodo: get, url: xxxx, altro_info: yyyy}.

Ora voglio assemblare un po 'di risposta in file. Il problema è che non posso semplicemente aprire e scrivere quando ogni richiesta finisce, che io costoso e i dati non sono in ordine corretto.

Suppongo che dovrei essere numerato tutte le richieste, la risposta della cache in ordine, aprire un greenlet per loop e assemblare i file, il codice pseudo potrebbe essere così:

max_chunk=1000
data=[]
def wait_and_assemble_file(): # a loop
    while True:
        if len(data)==28:
            f= open('test.txt','a')
            for d in data:
                f.write(d)
            f.close()
        gevent.sleep(0)

def after_request(response, index): # Execute after every request ends
    data[index]=response  # every response is about 5-25k

C'è una soluzione migliore? Esistono migliaia di richieste simultanee e dubito che l'uso della memoria possa crescere troppo velocemente, o troppi loop contemporaneamente o qualcosa di inaspettatamente.

Aggiornare:

I codici sopra sono solo dimostrare come fanno la memorizzazione nella cache dei dati e la scrittura di file. Nella situazione pratica, ci sono forse 1cento cicli per aspettare la memorizzazione nella cache e scrivere su file diversi.

Aggiornamento2

@It ninja suggerisce di utilizzare il sistema coda, quindi scrivo un'alternativa usando Redis:

def after_request(response, session_id, total_block_count ,index): # Execute after every request ends
    redis.lpush(session_id, msgpack.packb({'index':index, 'content':response}))  # save data to redid

    redis.incr(session_id+':count')
    if redis.get(session_id+':count') == total_block_count: # which means all data blocks are prepared
        save(session_name)


def save(session_name):
  data_array=[]
  texts = redis.lrange(session_name,0,-1)
  redis.delete(session_name)
  redis.delete(session_name+':count')
  for t in texts:
    _d = msgpack.unpackb(t)
    index = _d['index']
    content = _d['content']
    data_array[index]=content

  r= open(session_name+'.txt','w')
  [r.write(i) for i in data_array]
  r.close()

Sembra un po 'meglio, ma dubito che salvare grandi dati in Redis è una buona idea, spero in un ulteriore suggerimento!

È stato utile?

Soluzione

Qualcosa del genere può essere gestito meglio con un sistema di coda, invece di ogni thread che ha il proprio gestore di file. Questo perché puoi imbatterti in condizioni di gara quando si scrive questo file a causa di ogni thread che ha il proprio gestore.

Per quanto riguarda le risorse, ciò non dovrebbe consumare troppe risorse diverse dal tuo disco, supponendo che le informazioni passate al file non siano estremamente grandi (Python è davvero bravo al riguardo). Se ciò rappresenta un problema, leggere in memoria il file in blocchi (e scrivere proporzionalmente in blocchi) può ridurre notevolmente questo problema, purché questo sia disponibile come opzione per carichi di file.

Altri suggerimenti

Dipende dalla dimensione dei dati. Se è molto grande, può rallentare il programma con tutta la struttura in memoria.

Se la memoria non è un problema, dovresti mantenere la struttura in memoria invece di leggere tutto il tempo da un file. Apri un file ancora e ancora con la richiesta di concorrenza non è una buona soluzione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top