Завершить несколько потоков, когда какой-либо поток завершает задачу
Я новичок как для python, так и для потоков. Я написал код python, который работает как искатель веб-страниц и ищет сайты для определенного ключевого слова. Мой вопрос в том, как я могу использовать потоки для одновременного запуска трех разных экземпляров моего класса. Когда один из экземпляров находит ключевое слово, все три должны закрывать и останавливать сканирование в Интернете. Вот какой код.
class Crawler:
def __init__(self):
# the actual code for finding the keyword
def main():
Crawl = Crawler()
if __name__ == "__main__":
main()
Как я могу использовать потоки для того, чтобы Crawler выполнял три разных обхода одновременно?
Ответы
Ответ 1
Кажется, что нет (простой) способ прервать поток в Python.
Вот простой пример одновременного запуска нескольких HTTP-запросов:
import threading
def crawl():
import urllib2
data = urllib2.urlopen("http://www.google.com/").read()
print "Read google.com"
threads = []
for n in range(10):
thread = threading.Thread(target=crawl)
thread.start()
threads.append(thread)
# to wait until all three functions are finished
print "Waiting..."
for thread in threads:
thread.join()
print "Complete."
С дополнительными накладными расходами вы можете использовать multi-process aproach, более мощный и позволяющий прекратить поточно-подобные процессы.
Я добавил пример, чтобы использовать это. Я надеюсь, что это будет полезно для вас:
import multiprocessing
def crawl(result_queue):
import urllib2
data = urllib2.urlopen("http://news.ycombinator.com/").read()
print "Requested..."
if "result found (for example)":
result_queue.put("result!")
print "Read site."
processs = []
result_queue = multiprocessing.Queue()
for n in range(4): # start 4 processes crawling for the result
process = multiprocessing.Process(target=crawl, args=[result_queue])
process.start()
processs.append(process)
print "Waiting for result..."
result = result_queue.get() # waits until any of the proccess have `.put()` a result
for process in processs: # then kill them all off
process.terminate()
print "Got result:", result
Ответ 2
Запуск потока легко:
thread = threading.Thread(function_to_call_inside_thread)
thread.start()
Создайте объект события для уведомления, когда вы закончите:
event = threading.Event()
event.wait() # call this in the main thread to wait for the event
event.set() # call this in a thread when you are ready to stop
Как только событие было запущено, вам нужно добавить методы stop() к вашим искателям.
for crawler in crawlers:
crawler.stop()
И затем подключитесь к потокам
thread.join() # waits for the thread to finish
Если вы выполняете какое-либо количество такого рода программирования, вам нужно посмотреть на модуль eventlet. Он позволяет писать "резьбовой" код без многих недостатков потоковой передачи.
Ответ 3
Прежде всего, если вы новичок в python, я бы не рекомендовал обращать внимание на потоки. Привыкнуть к языку, а затем решить многопоточность.
С учетом сказанного, если ваша цель состоит в том, чтобы распараллелить (вы сказали, что "запускайте одновременно" ), вы должны знать, что в python (или, по крайней мере, в реализации по умолчанию, CPython) несколько потоков не будут действительно выполняются параллельно, даже если доступны несколько процессорных ядер. Прочтите на GIL (Global Interpreter Lock) для получения дополнительной информации.
Наконец, если вы все еще хотите продолжить, проверьте документацию Python для модуля потоковой передачи. Я бы сказал, что документы Python так же хороши, как и ссылки, с большим количеством примеров и объяснений.
Ответ 4
Для этой проблемы вы можете использовать либо модуль потоковой передачи (который, как говорили другие, не будет выполнять поточную передачу из-за GIL), либо модуль многопроцессорности (в зависимости от того, какую версию Python вы используете). У них очень похожие API, но я рекомендую многопроцессорность, поскольку это больше Pythonic, и я нахожу, что общение между процессами с Pipes довольно легко.
Вы хотите иметь свой основной цикл, который будет создавать ваши процессы, и каждый из этих процессов должен запускать ваш искатель, чтобы он возвращался к основному потоку. Ваш процесс должен прослушивать сообщение на трубке, выполнять обход и отправлять сообщение по каналу, если он что-то находит (перед завершением). Ваш основной цикл должен пересекать каждую из труб обратно, слушая это сообщение "нашел что-то". Как только он услышит это сообщение, он должен отправить его по каналам в остальные процессы, а затем дождаться их завершения.
Дополнительную информацию можно найти здесь: http://docs.python.org/library/multiprocessing.html
Ответ 5
Прежде всего, потоки не являются решением в Python. Из-за GIL Threads работает не параллельно. Таким образом, вы можете обрабатывать это с помощью многопроцессорной обработки, и вы будете ограничены количеством процессорных ядер.
Какова цель вашей работы? Вы хотите иметь сканера? Или у вас есть какие-то академические цели (изучение потоков и Python и т.д.)?
Еще один момент, Crawl тратить больше ресурсов, чем другие программы, так что продажа вашего обхода?