5

目標:redisからのデータポップを処理するいくつかのグリーンレットワーカーを生成します(redisからポップしてからキューに入れます)

実行環境:ubuntu 12.04 PYTHON VER:2.7 GEVENT VER:1.0 RC2 REDIS VER:2.6.5 REDIS-PY VER:2.7.1

from gevent import monkey; monkey.patch_all()
import gevent
from gevent.pool import Group
from gevent.queue import JoinableQueue
import redis

tasks = JoinableQueue()
task_group = Group()

def crawler():
    while True:
        if not tasks.empty():
            print tasks.get()
            gevent.sleep()

task_group.spawn(crawler)
redis_client = redis.Redis()
data = redis_client.lpop('test') #<----------Block here
tasks.put(data)

redisからデータをポップしようとしましたが、ブロックされました。例外は発生しませんでした。spawnメソッドをフリーズして削除するだけで、機能します。何が起こったのか混乱します。plzヘルプ!thk u!

4

1 に答える 1

10

gevent は協調的な軽量プロセス (スレッドではありません) を提供します。その結果、どこかに無限ループがあり、スケジューラが再入力されない場合、プログラムは CPU コアの 100% を使用してブロックされます。

あなたの例では、問題はクローラー ループを定義した方法です。明らかに、タスクが空の場合は無限ループになります。また、(必要な yield 操作を実行する) gevent.sleep 呼び出しは、タスクが空でない場合にのみ呼び出されるため、スケジューラが再入力されることはありません。

Redis クライアントによって接続が遅延されるため、lpop コマンドでブロックされているようです。イベントのシーケンスは次のとおりです。

  • タスク グループが生成されます。しかし、グリーンレットはまだ予定されていません
  • redis_client はビルドされていますが、実際の接続が遅延しているため、まだ I/O を生成していません
  • lpop が呼び出されます。今回は、Redis クライアントが接続と lpop への応答を待たなければならないため、接続が本当に必要です。したがって、スケジューラに譲ります
  • スケジューラーがクローラー ワーカーをアクティブ化する
  • タスク キューがまだ空であるため、無限ループ

ループ自体 (if の後) に gevent.sleep() を配置すると、より適切に機能しますが、デキューアを実装する方法としては依然として非効率的です。このようなものははるかに良いでしょう:

def crawler():
    while True:
        x = tasks.get()
        try:
            print "Crawler: ",x
        finally:
            tasks.task_done()

get() 呼び出しはワーカーをブロックしているため、キューが空の間、ワーカーとスケジューラーの間のピンポン ゲームを回避します。

于 2012-12-29T10:37:26.677 に答える