Проблема с многопроцессорностью в Windows 10

#python #multiprocessing #windows-10 #pool

#python #многопроцессорность #windows-10 #Бассейн

Вопрос:

Я пытаюсь определить размер домашних страниц списка сайтов, используя многопроцессорность. Ниже приведен код :

 import time
from multiprocessing import Pool, TimeoutError

start = time.time()


def sitesize(url):
    for url in sites:
        with urllib.request.urlopen(url) as u:
            page = u.read()
            print(url, len(page))


sites = [
    'https://www.yahoo.com',
    'http://www.cnn.com',
    'http://www.python.org',
    'http://www.jython.org',
    'http://www.pypy.org',
    'http://www.perl.org',
    'http://www.cisco.com',
    'http://www.facebook.com',
    'http://www.twitter.com',
    'http://arstechnica.com',
    'http://www.reuters.com',
    'http://www.abcnews.com',
    'http://www.cnbc.com',
]

if __name__ == '__main__': 

    with Pool(processes=4) as pool:
        for result in pool.imap_unordered(sitesize, sites):
            print(result)

print(f'Time taken : {time.time() - start}')
  

У меня ноутбук на Windows 10 с запущенным Python 3.9. Я не использую venv.

Этот код переходит в цикл — выполняется 4 раза и занимает в 4 раза больше времени.

В чем здесь ошибка? Кто-нибудь может помочь?

Заранее спасибо

Sachin

Ответ №1:

Я думаю, вы неправильно поняли, как pool.imap_unordered работает, предоставленная функция будет вызвана с одним из значений из sites , тогда как в вашем случае вы фактически полностью отбрасываете предоставленное url и выполняете цикл по всем значениям в sites списке.

Вы должны просто сделать

 def sitesize(url):
    with urllib.request.urlopen(url) as u:
        page = u.read()
        print(url, len(page))
  

Смотрите документ.

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

1. Большое спасибо — это решило проблему. Время все еще не 1/4, но я думаю, что это нормально. Это примерно в 0,5 раза больше, что приемлемо.

2. @Sachin Время выполнения D 1/4 не ожидается. При многопроцессорной обработке вы получаете некоторые дополнительные накладные расходы (межпроцессное взаимодействие, планирование, блокировка / управление общими ресурсами, такими как стандартный вывод и сетевые стеки).

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

Ответ №2:

Несколько проблем:

 def sitesize(url):
    result = {}
    for url in sites:
        with urllib.request.urlopen(url) as u:
            page = u.read()
            result[url] = len(page)
    return result
  
  • sitesize ничего не возвращает -> смотрите выше, что вам нужно иметь
  • нет необходимости в цикле for result in pool.imap_unordered(sitesize, sites): —> изменить на result = pool.map(sitesize, sites)

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

1. pool.imap_unordered(sitesize, сайты) возвращает итератор. Если я удалю цикл for, как он вернет результат?

2. почему бы вместо этого не использовать map?

3. Хорошо, вы предлагаете мне создать список с помощью map? Я не ищу этого. Я просто просматриваю выходные данные, которые печатают URL и размер файла. Без многопроцессорности код прост и выполняется за 11 секунд на моей машине. При многопроцессорности в соответствии с моим кодом требуется 44 секунды, и каждый URL-адрес выполняется 4 раза.

4. Если вы пойдете моим путем, это займет 11/4 секунды, поскольку каждое ядро будет обрабатывать 1/4 списка URL-адресов одновременно.

5. Попробовал оба предложения. Код возвращает словарь (как и ожидалось) URL-адреса и размера файла. Но это занимает почти 72 секунды…