Как заставить поток ждать в Python?

1

У меня есть следующий код:

        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 с пределом того, сколько потоков может выполнить его в одно и то же время.

  • 0
    Знаете ли вы о GIL в большинстве реализаций Python?
  • 0
    @BasileStarynkevitch да, но это не имеет значения здесь. Моя проблема, когда вызывается GET, а затем происходит переключение контекста в другой поток. Я хочу ограничить эту возможность, позволяя выполнять только 10 потоков.
Теги:
multithreading

1 ответ

1
Лучший ответ

Мы можем использовать 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
  • 0
    Спасибо. на самом деле ваш ответ помог мне найти гораздо более простое решение ... max_workers = num_of_pages был неверным. изменение его на cpu_count () решило мою проблему. Только 4 потока создаются каждый раз. Когда один закончен, другой создается.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню