Несколько дней назад я задал вопрос о SO о помощи в разработке парадигмы для структурирования нескольких HTTP-запросов
Вот сценарий. Я хотел бы иметь систему с несколькими производителями и потребителями. Мои продюсеры просматривают и очищают несколько сайтов и добавляют найденные ссылки в очередь. Поскольку я буду сканировать несколько сайтов, я хотел бы иметь несколько производителей / поисковых роботов.
Потребители / рабочие подпитываются из этой очереди, отправляют запросы TCP / UDP к этим ссылкам и сохраняют результаты в моей базе данных Django. Я также хотел бы иметь несколько рабочих, поскольку каждый элемент очереди полностью независим друг от друга.
Люди предложили использовать для этого библиотеку сопрограмм, то есть Gevent или Eventlet.Никогда не работая с сопрограммами, я читал, что, хотя парадигма программирования похожа на парадигмы потоков, активно выполняется только один поток, но когда происходят блокирующие вызовы, такие как вызовы ввода-вывода, стеки переключаются в памяти, а другие зеленые поток берет на себя управление, пока не встретит своего рода блокирующий вызов ввода-вывода. Надеюсь, я правильно понял? Вот код из одного из моих сообщений SO:
import gevent
from gevent.queue import *
import time
import random
q = JoinableQueue()
workers = []
producers = []
def do_work(wid, value):
gevent.sleep(random.randint(0,2))
print 'Task', value, 'done', wid
def worker(wid):
while True:
item = q.get()
try:
print "Got item %s" % item
do_work(wid, item)
finally:
print "No more items"
q.task_done()
def producer():
while True:
item = random.randint(1, 11)
if item == 10:
print "Signal Received"
return
else:
print "Added item %s" % item
q.put(item)
for i in range(4):
workers.append(gevent.spawn(worker, random.randint(1, 100000)))
# This doesn't work.
for j in range(2):
producers.append(gevent.spawn(producer))
# Uncommenting this makes this script work.
# producer()
q.join()
Это хорошо работает, потому что вызовы sleep
блокируют вызовы, и когда происходит событие sleep
, другой зеленый поток берет на себя. Это намного быстрее, чем последовательное выполнение.
Как видите, в моей программе нет кода, который намеренно передает выполнение одного потока другому потоку. Я не вижу, как это вписывается в сценарий выше, поскольку я хотел бы, чтобы все потоки выполнялись одновременно.
Все работает нормально, но я чувствую, что пропускная способность, которую я достиг с помощью Gevent / Eventlets, выше, чем у исходной последовательно выполняемой программы, но значительно ниже, чем та, которую можно было бы достичь с использованием реальной потоковой передачи.
Если бы мне пришлось повторно реализовать свою программу с использованием механизмов потоковой передачи, каждый из моих производителей и потребителей мог бы работать одновременно без необходимости менять стеки местами, как сопрограммы.
Следует ли повторно реализовать это с использованием потоковой передачи? Мой дизайн неправильный? Я не смог увидеть реальных преимуществ использования сопрограмм.
Может быть, мои концепции немного размыты, но это то, что я усвоил. Любая помощь или разъяснение моей парадигмы и концепций было бы замечательно.
Спасибо