У меня есть следующий код:
with ThreadPoolExecutor(max_workers=num_of_pages) as executor:
futh = [(executor.submit(self.getdata2, page, hed, data, apifolder,additional)) for page in pages]
for data in as_completed(futh):
datarALL = datarALL + data.result()
return datarALL
Параметр num_of_pages
не фиксирован, но обычно он getdata2
250. getdata2
func создает запросы GET и возвращает результаты каждой страницы:
Проблема в том, что все 250 страниц (потоков) создаются вместе. что означает 250 запросов GET, которые вызываются одновременно. Это вызывает перегрузку на сервере, поэтому я получаю много попыток из-за задержки ответа сервера, которая отключает вызов GET и повторяет его. Я хочу этого избежать.
Я думал о создании какой-то блокировки, которая предотвратит создание потоком/страницей запроса GET, если имеется более 10 активных запросов. В таком случае он будет ждать, пока слот не будет доступен.
Что-то вроде:
executing_now = []
def getdata2(...)
...
while len(executing_now)>10:
sleep(10)
executing_now.append(page)
response = requests.get(url, data=data, headers=hed, verify=False)
....
executing_now.remove(page)
return ...
Есть ли механизм для этого в Python? Это требует, чтобы потоки проверяли наличие общей памяти... Я хочу избежать многопоточных проблем, таких как тупик и т.д.
В основном, перетащите вызов GET с пределом того, сколько потоков может выполнить его в одно и то же время.
Мы можем использовать queue
для "подготовки" всех ваших страниц, а затем вы можете ограничить пул потоков любым количеством потоков, так как каждый поток будет извлекать нужную страницу из очереди:
# preparing here all you page objects
pages_queue = queue.Queue()
[pages_queue.put(page) for page in pages]
# ThreadPool - Each thread will take one page from queue, and when done, will fetch next one
with ThreadPoolExecutor(max_workers=10) as executor:
futh = [(executor.submit(self.getdata2, pages_queue, hed, data, apifolder,additional))]
for data in as_completed(futh):
datarALL = datarALL + data.result()
return datarALL
def getdata2(...)
...
try:
while True: # non blocking wait will raise Empty when queue is empty
page = pages_queue.get_nowait()
response = requests.get(page.url, data=data, headers=hed, verify=False)
....
return ...
except queue.Empty:
pass