Синхронизировать muti-threads в Python

Класс BrokenLinkTest в приведенном ниже коде делает следующее.

  • принимает URL-адрес веб-страницы
  • находит все ссылки на веб-странице.
  • получать заголовки ссылок одновременно (это делается для проверки, не повреждена ли ссылка)
  • print 'completed', когда все заголовки получены.

from bs4 import BeautifulSoup
import requests

class BrokenLinkTest(object):

    def __init__(self, url):
        self.url = url
        self.thread_count = 0
        self.lock = threading.Lock()

    def execute(self):
        soup = BeautifulSoup(requests.get(self.url).text)
        self.lock.acquire()
        for link in soup.find_all('a'):
            url = link.get('href')
            threading.Thread(target=self._check_url(url))
        self.lock.acquire()

    def _on_complete(self):
        self.thread_count -= 1
        if self.thread_count == 0: #check if all the threads are completed
            self.lock.release()
            print "completed"

    def _check_url(self, url):
        self.thread_count += 1
        print url
        result = requests.head(url)
        print result
        self._on_complete()


BrokenLinkTest("http://www.example.com").execute()

Можно ли выполнить concurrency/синхронизацию. Я сделал это с помощью threading.Lock. Это мой первый эксперимент с потоками python.

Ответ 1

def execute(self):
    soup = BeautifulSoup(requests.get(self.url).text)
    threads = []
    for link in soup.find_all('a'):
        url = link.get('href')
        t = threading.Thread(target=self._check_url, args=(url,))
        t.start()
        threads.append(t)
    for thread in threads:
        thread.join()

Вы можете использовать метод join для ожидания завершения всех потоков.

Примечание. Я также добавил начальный вызов и передал объект связанного метода в целевой параметр. В вашем исходном примере вы вызывали _check_url в основном потоке и передавали возвращаемое значение целевому параметру.

Ответ 2

Все потоки в Python работают на одном ядре, поэтому вы не будете получать какую-либо производительность, делая это таким образом. Также - очень неясно, что на самом деле происходит?

  • Вы никогда не запускаете нити, вы просто инициализируете его.
  • Нити сами по себе не имеют ничего общего, кроме уменьшения количества потоков

Вы можете получить производительность только в потоковом сценарии, если ваша программа выполняет работу с IO (отправка запросов, запись в файл и т.д.), где в то же время могут работать другие потоки.