Список возврата в исходном порядке при использовании параллельных фьючерсов

#python #multithreading

Вопрос:

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

 archive_url_list = ['https://web.archive.org/web/20171220002410/http://www.manueldrivingschool.co.uk:80/areas-covered-for-driving-lessons', 'https://web.archive.org/web/20210301102140/https://www.manueldrivingschool.co.uk/contact.php', 'https://web.archive.org/web/20210301102140/https://www.manueldrivingschool.co.uk/contact.php', 'https://web.archive.org/web/20171220002415/http://www.manueldrivingschool.co.uk:80/contact', 'https://web.archive.org/web/20160520140505/http://www.manueldrivingschool.co.uk:80/about.php', 'https://web.archive.org/web/20180102123922/http://www.manueldrivingschool.co.uk:80/about']

import waybackpy
import concurrent.futures

archive_h1_list = []
def get_archive_h1(h1_url):
    html = urlopen(h1_url)
    bsh = BeautifulSoup(html.read(), 'lxml')
    return bsh.h1.text.strip()

def concurrent_calls():
    with concurrent.futures.ThreadPoolExecutor(max_workers=CONNECTIONS) as executor:
        f1 = (executor.submit(get_archive_h1, h1_url) for h1_url in archive_url_list)
        for future in concurrent.futures.as_completed(f1):
            try:
                data = future.result()
                archive_h1_list.append(data)
            except Exception:
                archive_h1_list.append("No Data Received!")
                pass

if __name__ == '__main__':
    concurrent_calls()
    print(archive_h1_list)
 

Я попытался создать второй список для добавления исходного URL-адреса по мере выполнения кода в надежде, что смогу привязать его к факту, но все, что я получаю, — это пустой список. Новичок в параллельных фьючерсах, надеюсь, что есть стандартный способ.

Ответ №1:

Вместо генератора с ThreadPoolExecutor.submit , используйте ThreadPoolExecutor.map для заказа:

 def concurrent_calls():
    with concurrent.futures.ThreadPoolExecutor(max_workers=CONNECTIONS) as executor:
        f1 = executor.map(get_archive_h1, archive_url_list)
        ...
 

Это гораздо эффективнее.

Комментарии:

1. Спасибо, спасибо за ответ. Я только что попробовал использовать карту, как предлагалось, но это не работает. Я получаю: urllib.ошибка. HTTPError: Ошибка HTTP 404: Страница не найдена, я снова включаю свой код, и это не вызывает проблем. Я попробую еще немного отладить и выяснить, что происходит.

2. @LeeRoy Это не моя проблема с кодами , это проблема с вашей функцией