В ThreadpoolExecotor отсутствуют некоторые строки в python

#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 примерно половина из них завершилась неудачей. Вы должны попробовать и посмотреть, какая скорость работает лучше всего — вы всегда можете повторно отправлять неудачные запросы, но лучше найти максимально возможную скорость без каких-либо сбоев вообще.