数日前、複数のHTTPリクエストを構造化するためのパラダイムの設計を支援することについてSOについて質問しました。
これがシナリオです。マルチプロデューサー、マルチコンシューマーのシステムが欲しいのですが。私のプロデューサーはいくつかのサイトをクロールしてスクレイプし、見つけたリンクをキューに追加します。複数のサイトをクロールするので、複数のプロデューサー/クローラーが必要です。
コンシューマー/ワーカーはこのキューをフィードし、これらのリンクに対してTCP / UDP要求を行い、結果をDjangoDBに保存します。また、各キューアイテムは完全に独立しているため、複数のワーカーが必要です。
人々は、これにコルーチンライブラリ、つまりGeventまたはEventletを使用することを提案しました。コルーチンを使用したことがないので、プログラミングパラダイムはスレッドパラダイムに似ていますが、アクティブに実行されているスレッドは1つだけですが、I / O呼び出しなどのブロック呼び出しが発生すると、スタックはメモリ内で切り替えられ、もう1つはグリーンになります。スレッドは、ある種のブロッキングI/O呼び出しに遭遇するまで引き継ぎます。うまくいけば、私はこれを正しくしましたか?これが私のSO投稿の1つからのコードです:
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を使用して達成したスループットは、元の順次実行プログラムよりも高くなりますが、実際のスレッドを使用して達成できるスループットよりも大幅に低くなります。
スレッドメカニズムを使用してプログラムを再実装する場合、コルーチンのようにスタックをスワップインおよびスワップアウトする必要なしに、プロデューサーとコンシューマーのそれぞれが同時に作業できます。
これは、スレッドを使用して再実装する必要がありますか?私のデザインは間違っていますか?コルーチンを使用することの本当の利点を理解できませんでした。
たぶん私の概念は少し泥だらけですが、これは私が同化したものです。私のパラダイムと概念の助けや明確化は素晴らしいでしょう。
ありがとう