Use Python, ¿debo almacenar en caché los datos grandes en la matriz y escribir para archivar una vez?

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

  •  28-07-2022
  •  | 
  •  

Pregunta

Tengo páginas de descarga de Crawler de Gevent Powered todo el tiempo. El patrón de productores de Crawler adopta, que alimento la cola con datos como este {método: get, url: xxxx, other_info: aaa yyyy}.

Ahora quiero reunir alguna respuesta en los archivos. El problema es que no puedo abrir y escribir cuándo termina cada solicitud, que IO es costosa y los datos no están en orden correcto.

Supongo que puede ser que numere todas las solicitudes, la respuesta de caché en orden, abra un Greenlet para enrollar y ensamblar archivos, el código de pseudo puede ser así:

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

¿Hay mejor solución? Hay miles de solicitudes concurrentes, y dudo que el uso de la memoria sea creciente demasiado rápido, o demasiados bucles al mismo tiempo, o algo inesperadamente.

Actualizar:

Los códigos anteriores solo demuestran cómo lo hace el almacenamiento en caché de datos y la redacción de archivos. En una situación práctica, tal vez se ejecutaran los 1 cien bucles para esperar en caché y escribir en diferentes archivos.

Actualización2

@IT Ninja sugiere usar el sistema de cola, por lo que escribo una 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()

Se ve un poco mejor, pero dudo que si guardar datos grandes en Redis es una buena idea, ¡espero más sugerencias!

¿Fue útil?

Solución

Algo así puede manejarse mejor con un sistema de cola, en lugar de que cada hilo tenga su propio manejador de archivos. Esto se debe a que puede encontrarse con condiciones de carrera al escribir este archivo debido a que cada hilo tiene su propio controlador.

En cuanto a los recursos, esto no debería consumir demasiados recursos que no sean su disco, suponiendo que la información que se transmite al archivo no es extremadamente grande (Python es realmente buena al respecto). Sin embargo, si esto plantea un problema, leer en la memoria el archivo en fragmentos (y escribir proporcionalmente en fragmentos) puede reducir en gran medida este problema, siempre que esto esté disponible como una opción para las cargas de archivo.

Otros consejos

Depende del tamaño de los datos. Si es muy grande, puede ralentizar el programa que tiene toda la estructura en la memoria.

Si la memoria no es un problema, debe mantener la estructura en la memoria en lugar de leer todo el tiempo de un archivo. Abra un archivo una y otra vez con la solicitud de concurrentes no es una buena solución.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top