Я использую запросы и потоки в python, чтобы делать некоторые вещи. Мой вопрос: действительно ли этот код работает в многопоточном режиме и безопасно ли его использовать? Я испытываю некоторое замедление с течением времени. Примечание. Я не использую этот точный код, но мой делает похожие вещи.
import time
import requests
current_threads = 0
max_threads = 32
def doStuff():
global current_threads
r = requests.get('https://google.de')
current_threads-=1
while True:
while current_threads >= max_threads:
time.sleep(0.05)
thread = threading.Thread(target = doStuff)
thread.start()
current_threads+=1
@martineau Сэр, могу я обратить ваше внимание на здесь и награда по аналогичной проблеме!
@martineau Спасибо за ответ, но почему именно ThreadPoolExecutor лучше?
Брайан: Ну, навскидку, помимо того, что не требует изменения глобальных переменных потенциально небезопасным способом, он не создает неограниченного количества потоков, это отлаженный встроенный, написанный экспертами, и был разработан именно для того, чтобы делать добрые дела. кажется, вы пытаетесь.
Брайан: Этот отвечать к другому вопросу также содержит хорошее объяснение того, как это лучше.






Причин проблемы, с которой вы столкнулись, может быть несколько. Я не эксперт в Python, но я вижу потенциал для ряда причин замедления. Возможные причины, о которых я могу думать, следующие:
В зависимости от размера данных, которые вы загружаете, вы потенциально можете перегрузить свою пропускную способность. Трудно доказать, не видя точного кода, который вы используете, и того, что ваш код делает, и не зная вашей пропускной способности.
Вроде как подключен к первому, но если вашим файлам требуется некоторое время, чтобы спуститься на поток, он может засориться в:
while current_threads >= max_threads:
time.sleep(0.05)
вы можете попробовать уменьшить максимальное количество потоков и посмотреть, поможет ли это, хотя может и нет, если файлы требуют времени для загрузки.
Проблема может быть не в вашем коде или вашей пропускной способности, а в сервере, с которого вы извлекаете файлы, если этот сервер перегружен, это может замедлить вашу передачу.
Брандмауэры, IPS, IDS, политики на сервере могут ограничивать ваши запросы. Если вы сделаете слишком много запросов, чтобы быстро все с одного и того же IP-адреса, сетевое оборудование на стороне сервера может принять это за своего рода DoS-атаку и заблокировать ваши запросы в ответ.
К сожалению, Python, по сравнению с другими языками более низкого уровня, такими как C# или C++, не так хорош в многопоточности. Это связано с тем, что называется GIL (глобальная блокировка интерпретатора), которая вступает в игру, когда вы получаете доступ к одним и тем же данным или манипулируете ими в нескольких потоках. Это довольно обширная тема сама по себе, но если вы хотите прочитать об этом, взгляните на эту ссылку.
https://medium.com/practo-engineering/threading-vs-multiprocessing-in-python-7b57f224eadb
Извините, я ничем больше не могу помочь, но это все, что я могу сказать по этому вопросу, учитывая предоставленную информацию.
Сэр, могу я обратить ваше внимание на здесь и награда по аналогичной проблеме!
Конечно, вы используете несколько потоков и при условии, что они не обращаются к одним и тем же ресурсам или не изменяют их, вы, вероятно, «безопасны».
Всякий раз, когда я обращаюсь к внешним ресурсам (т. е. использую запросы), я всегда рекомендую asyncio, а не ванильную многопоточность, поскольку она позволяет переключать настраиваемый контекст (везде, где у вас есть «ожидание», вы переключаете контексты, тогда как в ванильном многопоточности переключение между потоками определяется ОС и может быть не оптимальным) и сократить накладные расходы (вы используете только ОДИН поток).
Сэр, могу я обратить ваше внимание на здесь и награда по аналогичной проблеме!
Да, он работает с несколькими потоками. Было бы лучше, если бы вы использовали
concurrent.futures.ThreadPoolExecutorсmax_workers=max_threads. Код, который у вас есть, продолжает создавать новые потоки, что может быть причиной возможного замедления. Что касается безопасности, изменение такой общей переменной без чего-то вродеLockдля предотвращения одновременного доступа также может быть проблематичным и ненужным, если вы используетеThreadPoolExecutor.