Utilisez Python, dois-je mettre en cache de grandes données dans le tableau et écrire dans un fichier une fois?

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

  •  28-07-2022
  •  | 
  •  

Question

J'ai tout le temps une pages de téléchargement de robottes alimentées sur gevent. Le Crawler adopte le modèle producteur-consommateur, que je nourris la file d'attente avec des données comme celle-ci {méthode: get, url: xxxx, autre_info: yyyy}.

Maintenant, je veux assembler une réponse dans les fichiers. Le problème est que je ne peux pas simplement ouvrir et écrire lorsque chaque demande se termine, que IO coûte et que les données ne sont pas dans un ordre correct.

Je suppose que je dois numéroter toutes les demandes, la réponse au cache dans l'ordre, ouvrir un vert pour faire boucle et assembler des fichiers, le code pseudo peut être comme ceci:

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

Y a-t-il une meilleure solution? Il y a des milliers de demandes simultanées, et je doute que l'utilisation de la mémoire puisse se développer trop rapidement, ou trop de boucle en même temps, ou quelque chose de manière inattendue.

Mise à jour:

Les codes ci-dessus démontrent simplement comment la mise en cache des données et la rédaction de fichiers font. Dans une situation pratique, il y a peut-être 1 cents boucle pour attendre le cache complet et écrire dans différents fichiers.

Mise à jour2

@It ninja suggère d'utiliser le système de file d'attente, donc j'écris une alternative à l'aide de 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()

Ça a l'air un peu mieux, mais je doute que la sauvegarde de grandes données dans Redis soit une bonne idée, espérez plus de suggestions!

Était-ce utile?

La solution

Quelque chose comme ça peut être mieux géré avec un système de file d'attente, au lieu que chaque thread ait son propre gestionnaire de fichiers. En effet

En ce qui concerne les ressources, cela ne devrait pas consommer trop de ressources autres que votre disque écrit, en supposant que les informations transmises au fichier ne sont pas extrêmement importantes (Python est vraiment bon à ce sujet). Si cela pose cependant un problème, la lecture en mémoire du fichier en morceaux (et l'écriture proportionnellement en morceaux) peut considérablement réduire ce problème, tant que cela est disponible en option pour les téléchargements de fichiers.

Autres conseils

Cela dépend de la taille des données. S'il est très grand, cela peut ralentir le programme ayant toute la structure en mémoire.

Si la mémoire n'est pas un problème, vous devez garder la structure en mémoire au lieu de lire tout le temps à partir d'un fichier. Ouvrez un fichier encore et encore avec les concurrents de la demande n'est pas une bonne solution.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top