Use Python, devo cachar grandes dados na matriz e gravar para arquivar uma vez?

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

  •  28-07-2022
  •  | 
  •  

Pergunta

Eu tenho um rastreador de rastreamento com Gevent, download de páginas o tempo todo. O padrão adota o padrão do produtor-consumidor, que eu alimento a fila com dados como este {Método: get, url: xxxx, outros_info: yyyy}.

Agora eu quero montar alguma resposta em arquivos. O problema é que não posso simplesmente abrir e escrever quando todas as solicitações terminam, que IO é caro e os dados não estão em ordem correta.

Presumo que possa ser que eu deveria numerar todas as solicitações, resposta do cache em ordem, abrir uma Greenlet para fazer loop e montar arquivos, o código pseudo pode ser assim:

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

Existe uma solução melhor? Existem milhares de solicitações simultâneas, e duvido que o uso da memória possa crescer muito rápido, ou muito loop ao mesmo tempo, ou algo inesperadamente.

Atualizar:

Os códigos acima são apenas demonstrar como o cache de dados e a redação de arquivos. Em situação prática, há talvez 1 cem do loop de corrida para aguardar o cache completo e escreva em diferentes arquivos.

Atualização2

@It ninja sugere usar o sistema de filas, então escrevo uma 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()

Parece um pouco melhor, mas duvido que salvar grandes dados no Redis seja uma boa ideia, espere mais sugestões!

Foi útil?

Solução

Algo assim pode ser melhor tratado com um sistema de filas, em vez de cada thread ter seu próprio manipulador de arquivos. Isso ocorre porque você pode encontrar condições de corrida ao escrever esse arquivo devido a cada thread ter seu próprio manipulador.

No que diz respeito aos recursos, isso não deve consumir muitos recursos além do seu disco, assumindo que as informações que estão sendo passadas para o arquivo não são extremamente grandes (o Python é realmente bom sobre isso). Se isso representar um problema, a leitura da memória no arquivo em pedaços (e a gravação proporcionalmente em pedaços) pode reduzir bastante esse problema, desde que esteja disponível como uma opção para uploads de arquivo.

Outras dicas

Depende do tamanho dos dados. Se muito grande, pode diminuir o programa com toda a estrutura na memória.

Se a memória não for um problema, você deve manter a estrutura na memória em vez de ler o tempo todo a partir de um arquivo. Abra um arquivo repetidamente com a solicitação de concorrentes não é uma boa solução.

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