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!