#python #multithreading #threadpoolexecutor
#питон #многопоточность #потокисполнитель
Вопрос:
Я экспериментировал с многопоточностью и не мог понять, почему она пропускает много строк? пожалуйста, помогите мне улучшить мой код. Могу ли я использовать shutodown fn для его улучшения?
import concurrent.futures import requests import json import time URLList = [] for i in range(100): URLList.append("https://randomuser.me/api/") def getName(urlApi): print(requests.get(urlApi).json()["results"][0]["name"]) def main(): with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor: executor.submit(getName) executor.map(getName , URLList) start_time = time.time() main() midtime = time.time() - start_time print(f"--- {midtime} seconds ---")
Вывод — это несколько случайных строк, а не 100 строк
{'title': 'Miss', 'first': 'Lily', 'last': 'Johnson'} {'title': 'Mr', 'first': 'میلاد', 'last': 'سلطانی نژاد'} {'title': 'Ms', 'first': 'Celina', 'last': 'Henry'} {'title': 'Mr', 'first': 'آرمین', 'last': 'سالاری'} {'title': 'Ms', 'first': 'Stans', 'last': 'Ordelman'} {'title': 'Mr', 'first': 'Matthäus', 'last': 'Hilger'} {'title': 'Ms', 'first': 'Marta', 'last': 'Flores'} {'title': 'Mr', 'first': 'Alex', 'last': 'Gutierrez'} {'title': 'Mr', 'first': 'Hugo', 'last': 'Walker'} {'title': 'Mr', 'first': 'Vincent', 'last': 'Campbell'} {'title': 'Mr', 'first': 'آریا', 'last': 'صدر'} {'title': 'Mr', 'first': 'Lode', 'last': 'Mulderij'} {'title': 'Miss', 'first': 'Manuela', 'last': 'Rubio'} {'title': 'Mr', 'first': 'Jacob', 'last': 'Wang'} {'title': 'Mr', 'first': 'رضا', 'last': 'کامروا'} {'title': 'Mr', 'first': 'سهیل', 'last': 'مرادی'} {'title': 'Miss', 'first': 'Kristin', 'last': 'Roberts'} {'title': 'Mr', 'first': 'Allen', 'last': 'Weaver'} {'title': 'Miss', 'first': 'Cathy', 'last': 'Johnston'} {'title': 'Mr', 'first': 'Isaías', 'last': 'da Paz'} {'title': 'Mr', 'first': 'Felix', 'last': 'Lam'} {'title': 'Mr', 'first': 'Julio', 'last': 'Chambers'} {'title': 'Mr', 'first': 'Felix', 'last': 'Johansen'} {'title': 'Mr', 'first': 'Ruben', 'last': 'Mora'} {'title': 'Mr', 'first': 'Marco', 'last': 'Diaz'} {'title': 'Ms', 'first': 'Yvonne', 'last': 'Sims'} {'title': 'Mr', 'first': 'Conrad', 'last': 'Owren'} {'title': 'Mr', 'first': 'آرسین', 'last': 'گلشن'} {'title': 'Mr', 'first': 'Aitor', 'last': 'Santos'} {'title': 'Ms', 'first': 'Sally', 'last': 'Bell'} {'title': 'Mr', 'first': 'Valentin', 'last': 'Marquez'} {'title': 'Mr', 'first': 'Jacob', 'last': 'Mortensen'} {'title': 'Monsieur', 'first': 'Nicolas', 'last': 'Lucas'}
Пожалуйста, помогите мне.
Ответ №1:
Я могу получить все 100 результатов при использовании следующего фрагмента:
def main(): with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor: results = [executor.submit(getName , x) for x in URLList] print(len(results))
Однако, когда я пытаюсь на самом деле взглянуть на результаты:
[result.result() for result in results]
Я получаю:
JSONDecodeError: Expecting value: line 1 column 1 (char 0)
Это связано с тем, что некоторые запросы на самом деле не возвращаются успешными.
Так что давайте попробуем getName
немного измениться, чтобы посмотреть, что произойдет, когда мы потерпим неудачу:
def getName(urlApi): request = requests.get(urlApi) try: return request.json()["results"][0]["name"] except: return request.text
И для нас получается, что для некоторых строк это:
lt;htmlgt; lt;headgt; lt;titlegt;Uh oh, something bad happenedlt;/titlegt; lt;/headgt; lt;body align='center'gt; lt;h1 align='center'gt;Uh oh, something bad happenedlt;/h1gt; lt;a class="twitter-timeline" data-width="450" data-height="700" data-theme="light" href="https://twitter.com/randomapi"gt;Tweets by randomapilt;/agt; lt;script async src="//platform.twitter.com/widgets.js" charset="utf-8"gt;lt;/scriptgt; lt;/bodygt; lt;/htmlgt;
Если вы попытаетесь сократить количество работников, вы увидите, что все больше запросов возвращаются успешными, что говорит о том, что вы столкнулись с некоторым ограничением скорости. В любом случае, что касается многопоточности, все работает правильно, и вы действительно отправляете сто запросов и получаете сто ответов. Просто некоторые из них не совсем те ответы JSON, которые вы надеялись получить.
При установке max_workers
на 1
я смог успешно получить все 100 ответов. Таким образом, запросы отправляются последовательно, но асинхронно, что по-прежнему параллельно и, следовательно, быстрее, чем просто отправлять их по одному, ожидая каждого ответа перед отправкой следующего запроса.
Имея max_workers
до 4, я все еще мог успешно получать 100% запросов, но max_workers=5
примерно половина из них завершилась неудачей. Вы должны попробовать и посмотреть, какая скорость работает лучше всего — вы всегда можете повторно отправлять неудачные запросы, но лучше найти максимально возможную скорость без каких-либо сбоев вообще.