Несколько дней назад я задал вопрос о SO о помощи мне разработать парадигму для структурирования несколько HTTP запросовразличия пропускной способности при использовании сопрограмм против пронизывающие
Вот сценарий. Я бы хотел, чтобы у вас была многопроцессорная многопользовательская система. Мои продюсеры сканируют и очищают несколько сайтов и добавляют ссылки, которые он находит в очередь. Поскольку я буду сканировать несколько сайтов, я хотел бы иметь несколько продюсеров/сканеров.
Потребители/работники передают эту очередь, делают запросы TCP/UDP на эти ссылки и сохраняют результаты в моем Django DB. Я также хотел бы иметь нескольких сотрудников, поскольку каждый элемент очереди полностью независим друг от друга.
Люди предложили использовать библиотеку сопрограммы для этого, например, 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, выше, чем исходная программа, работающая последовательно, но значительно ниже, чем можно было бы достичь с помощью реальной потоковой передачи.
Если бы я должен был выполнить повторную реализацию моей программы с использованием механизмов потоковой обработки, каждый из моих производителей и потребителей мог бы одновременно работать без необходимости свопить стеки внутрь и наружу как сопрограммы.
Должно ли это быть реализовано с использованием резьбы? Является ли мой дизайн неправильным? Я не видел реальных преимуществ использования сопрограмм.
Возможно, мои понятия немного грязные, но это то, что я усвоил. Любая помощь или разъяснение моей парадигмы и концепций будет отличной.
Благодаря
Почему бы не использовать несколько процессов? –
Я не знаю плюсов и минусов многопоточности против многопроцессорной обработки, поэтому я не знаю, хорошо ли это или нет. –
нет такой вещи, как «настоящая потоковая передача» (только один фактический поток ОС выполняется в любой момент времени) в программах Python, не прибегая к C-расширениям (или тяжелым ОС ОС) из-за глобальной блокировки интерпретатора. –