Панели прогресса параллельных загрузок в Python

#python-3.x #parallel-processing #download #concurrent.futures #tqdm

Вопрос:

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

 import requests
from requests.auth import HTTPBasicAuth
from pathlib import Path
from tqdm import *
from concurrent.futures import ThreadPoolExecutor, as_completed # for parallel downloads

class DownloadClass:

def __init__(self, url: str, usr: str, pwd: str):
    self.__file_url = url
    self.__usr = usr
    self.__pwd = pwd
    self.__req_skel = requests.Session()

def get_file_name(self):
    ... some stuff
    # returns the name of the targeted file using the request lib.

def get_file_size(self):
    ... some stuff
    # returns the file size of the targeted file using request lib

def download_file(self, dl_directory):
    _dl_dir = Path(dl_directory)
    _target_file = self.get_file_name()   '.zip'
    _dl_url =self.__file_url
    _file_size = self.get_file_size()

    with self.__req_skel.get(_dl_url, auth=HTTPBasicAuth(self.__usr, self.__pwd), stream=True) as stream:
        if stream.status_code == requests.codes.ok and _dl_dir.exists():
            with open(Path(_dl_dir / _target_file), 'wb') as writer:
                pbar = tqdm(total=int(_file_size))
                for data in stream.iter_content(chunk_size=1024):
                    writer.write(data)
                    pbar.update(len(data))
 

С помощью этого я могу последовательно загружать файлы, например:

 urls=[...] # many file-urls which I want to download
user = 'USERNAME'
password = 'PASSWORD'
dl_path = 'PATH_TO_DOWNLOAD_DIRECTORY'


# sequential download
for i in range(len(urls)):
    DownloadClass(urls[i], user, password).download_file(dl_path)
 

Это прекрасно работает, но я хочу загружать файлы параллельно, поэтому я выбрал параллельные фьючерсы:

 max_jobs = 3
with ThreadPoolExecutor(max_workers=max_jobs) as ex:
    futures = [ex.submit(DownloadClass(file_url, user, password).download_file, dl_path) for file_url in urls]
    for future in as_completed(futures):
        res = future.result()
 

По крайней мере, он выполняет 3 задания загрузки, выполняемых параллельно, но вывод терминала-это беспорядок, так как каждый ход загрузки каждого файла выводится на новую строку (вроде как перезаписывается). Я скорее хочу, чтобы в начальной строке был обновлен ход каждой загрузки, как показано здесь. Я нашел несколько примеров, которые просто объединяют общую длину параллельных задач и обновляют ход выполнения всей задачи, но это не то, что я хочу.