Как я могу изменить этот код, чтобы индикаторы выполнения отображались для каждого файла и каждая итерация составляла l oop? - PullRequest
3 голосов
/ 01 марта 2020

Я борюсь с тем, чтобы индикатор прогресса tqdm оставался и обновлялся, в отличие от записи в новую строку. Примечание. Я использую multiprocessing для распараллеливания моего кода, а tqdm находится внутри функции, которую распараллеливаю.

Я добавил оператор print, чтобы все файлы появлялись на моем терминале при запуске программы. Воспроизводимый пример ниже:

import multiprocessing
import time

from tqdm import tqdm
from joblib import Parallel, delayed


def run_file_analysis(text):
    cool = []
    for i in tqdm(range(0, 10), position = 0, leave = True, desc = f'Text : {text}'):
        print('')
        cool.append(i)
        time.sleep(1)

num_cores = multiprocessing.cpu_count()
ls = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']

if __name__ == "__main__":
    processed_list = Parallel(n_jobs=num_cores)(delayed(run_file_analysis)(i) for i in ls)

Текущий вывод: enter image description here

Желаемым выводом будут десять текстовых объектов - 1, 2, 3, ... , 10 и соответствующий индикатор прогресса обновления для каждого. Не 100 разных. Я попытался ответить на многие вопросы, связанные со стековым потоком, связанные с топиками c из tqdm и multiprocessing интеграции, но ни один из них не настолько прост, как хотелось бы. Любая помощь будет оценена.

1 Ответ

3 голосов
/ 03 марта 2020

Как уже обсуждалось в комментариях, вы не хотите добавлять дополнительную новую строку с оператором печати. Вместо этого вы хотите использовать аргумент position в tqdm. Вариант использования для разных потоков даже упоминается в документах .

position : int, optional
  Specify the line offset to print this bar (starting from 0)
  Automatic if unspecified. Useful to manage multiple bars at once (eg, from threads).

В настоящее время этот аргумент имеет значение 0, поэтому он будет запускать индикатор выполнения каждый раз, когда появляется новый. Вместо этого вы хотите использовать номер потока. Из-за простоты вы можете преобразовать данный текст в целое число и использовать его. Но это не рекомендуется для производства.

import multiprocessing
import time

from tqdm import tqdm
from joblib import Parallel, delayed


def run_file_analysis(text):
    cool = []
    for i in tqdm(range(0, 10), position=int(text), leave=True, desc = f'Text : {text}'):
        cool.append(i)
        time.sleep(1)

num_cores = multiprocessing.cpu_count()
ls = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']

if __name__ == "__main__":
    processed_list = Parallel(n_jobs=num_cores)(delayed(run_file_analysis)(i) for i in ls)

Если текст не может быть напрямую преобразован в целое число, можно использовать 'enumerate' и индекс может быть передан функции.

import multiprocessing
import time

from tqdm import tqdm
from joblib import Parallel, delayed


def run_file_analysis(text, job_number):
    cool = []
    for i in tqdm(range(0, 10), position=job_number, leave=True, desc = f'Text : {text}'):
        cool.append(i)
        time.sleep(1)

num_cores = multiprocessing.cpu_count()
ls = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']

if __name__ == "__main__":
    processed_list = Parallel(n_jobs=num_cores)(delayed(run_file_analysis)(text, i) for i, text in enumerate(ls))

Редактировать:

Некоторые условия гонки можно уменьшить, установив prefer='threads' для конструктора Parallel:

if __name__ == "__main__":
    processed_list = Parallel(n_jobs=num_cores, prefer="threads")(delayed(run_file_analysis)(text, i) for i, text in enumerate(ls))
...