2012-12-29 6 views
5

ZIEL: Spawn einige Greenlet Arbeiter befassen sich mit der Daten pop aus redis (von redis Pop und dann in die Warteschlange gestellt)GEVENT Block redis' socket Anfrage

RUNNING ENV: 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) 

versuchen, Daten aus redis Pop, aber es blocked..and keine Ausnahme ... nur einzufrieren und entfernen Spawn-Methode, es wird gearbeitet .. Ich fühle mich verwirrt, was passiert pened, plz Hilfe! Danke!

Antwort

9

gevent bietet kooperative leichte Prozesse (nicht Threads). Die Konsequenz ist, wenn Sie irgendwo eine Endlosschleife haben und der Scheduler nie wieder betreten wird, blockiert das Programm die Übernahme von 100% eines CPU-Kerns.

In Ihrem Beispiel ist das Problem, wie Sie die Crawler-Schleife definiert haben. Offensichtlich haben Sie eine Endlosschleife, wenn Aufgaben leer sind. Und weil der gevent.sleep-Aufruf (der die erforderliche Yield-Operation ausführen würde) nur aufgerufen wird, wenn die Tasks nicht leer sind, bedeutet dies, dass der Scheduler nie wieder betreten wird.

Es scheint auf dem lpop-Befehl zu blockieren, da die Verbindung vom Redis-Client verzögert wird. Die Reihenfolge der Ereignisse ist wie folgt:

  • die Aufgabengruppe wird erzeugt; aber kein Greenlet ist noch geplant
  • redis_client ist gebaut, aber es erzeugt noch keine I/O, da die tatsächliche Verbindung verzögert ist
  • lpop heißt; Diesmal ist die Verbindung wirklich notwendig, da der Redis-Client auf die Verbindung und die Antwort auf lpop warten muss; es ergibt sich daher an den Scheduler
  • der Scheduler aktiviert einen Crawler Arbeiter
  • Endlosschleife, da die Aufgaben Warteschlange

noch leer Wenn Sie die gevent.sleep() in der Schleife setzen sich (nach dem Wenn), wird es besser funktionieren, aber es ist immer noch ein ineffizienter Weg, ein Dequeuer zu implementieren. So etwas wie dies wäre viel besser:

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

Die get() Aufruf an die Arbeiter blockiert, so wird es das Ping-Pong-Spiel zwischen dem Arbeiter und dem Scheduler zu vermeiden, während die Warteschlange leer ist.

+0

Warum wird dies abgelehnt? – schlamar

+0

Ich weiß es nicht, aber ich stehe immer noch zu meiner Antwort ;-) –

Verwandte Themen