2

Я выполняю синтаксический анализ файла, который является задачей, связанной с процессором. Независимо от того, сколько файлов я бросаю в процессе, он использует не более 50 МБ ОЗУ. Задача parrallelisable, и я поставил его использовать параллельные фьючерсы ниже, чтобы разобрать каждый файл как отдельный процесс:Использование параллельных фьючерсов без исчерпания ОЗУ

from concurrent import futures 
    with futures.ProcessPoolExecutor(max_workers=6) as executor: 
     # A dictionary which will contain a list the future info in the key, and the filename in the value 
     jobs = {} 

     # Loop through the files, and run the parse function for each file, sending the file-name to it. 
     # The results of can come back in any order. 
     for this_file in files_list: 
      job = executor.submit(parse_function, this_file, **parser_variables) 
      jobs[job] = this_file 

     # Get the completed jobs whenever they are done 
     for job in futures.as_completed(jobs): 

      # Send the result of the file the job is based on (jobs[job]) and the job (job.result) 
      results_list = job.result() 
      this_file = jobs[job] 

      # delete the result from the dict as we don't need to store it. 
      del jobs[job] 

      # post-processing (putting the results into a database) 
      post_process(this_file, results_list) 

Проблема заключается в том, что, когда я запускаю это с помощью фьючерсов, ракеты использования RAM и до долго я закончил, и Python разбился. Это, вероятно, в значительной степени, потому что результаты parse_function имеют размер в несколько мегабайт. Как только результаты пройдут через post_processing, приложение больше не нуждается в них. Как вы можете видеть, я пытаюсь удалить del jobs[job], чтобы удалить элементы из jobs, но это не имеет значения, использование памяти остается неизменным и, похоже, увеличивается с той же скоростью.

Я также подтвердил, что это не потому, что он ждет от функции post_process, используя только один процесс, плюс бросает в time.sleep(1).

Там нет ничего в фьючерсных документах об управлении памятью, и в то время как краткий поиск показывает, что он пришел раньше в реальных приложениях фьючерсов (Clear memory in python loop и http://grokbase.com/t/python/python-list/1458ss5etz/real-world-use-of-concurrent-futures) - ответы не переводить на мой потребительном случае (все они озабочены таймаутами и т. п.).

Итак, как вы используете параллельные фьючерсы, не исчерпывая ОЗУ? (Python 3.5)

ответ

2

Я возьму выстрел (Может быть неправильное предположение ...)

Вы, возможно, потребуется представить вашу работу по крупицам, так как на каждом представить вы делаете копию parser_variables, который может привести к жеванию вашей оперативной памяти.

Здесь работает код с "< ----" на интересные части

with futures.ProcessPoolExecutor(max_workers=6) as executor: 
    # A dictionary which will contain a list the future info in the key, and the filename in the value 
    jobs = {} 

    # Loop through the files, and run the parse function for each file, sending the file-name to it. 
    # The results of can come back in any order. 
    files_left = len(files_list) #<---- 
    files_iter = iter(files_list) #<------ 

    while files_left: 
     for this_file in files_iter: 
      job = executor.submit(parse_function, this_file, **parser_variables) 
      jobs[job] = this_file 
      if len(jobs) > MAX_JOBS_IN_QUEUE: 
       break #limit the job submission for now job 

     # Get the completed jobs whenever they are done 
     for job in futures.as_completed(jobs): 

      files_left -= 1 #one down - many to go... <--- 

      # Send the result of the file the job is based on (jobs[job]) and the job (job.result) 
      results_list = job.result() 
      this_file = jobs[job] 

      # delete the result from the dict as we don't need to store it. 
      del jobs[job] 

      # post-processing (putting the results into a database) 
      post_process(this_file, results_list) 
      break; #give a chance to add more jobs <----- 
+0

Отличный ответ, спасибо. Это хорошо отразилось на пике использования ОЗУ приблизительно 140 МБ; Я никогда не рассматривал исходные данные как проблему (вы правы, они тоже очень большие). (Это было после того, как 20 минут интересовались, почему ваша не была действительно многопроцессорной, вы перечеркнули строку 'for job in ...', чтобы она была дочерней частью 'for this_file in ...' (исправлено теперь). * Примечание для дизайнеров Python: невидимые символы для критического синтаксиса - это не очень хорошая идея! * –

+0

Спасибо за редактирование, я спешил :) –

Смежные вопросы