2012-12-29 11 views
5

OBIETTIVO: deporre le uova un accordo qualche operaio greenlet con la comparsa di dati da Redis (pop da Redis e poi mettere in coda)gevent richiesta presa blocco Redis'

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

cercare di pop dati da Redis, ma blocked..and non fa eccezione sollevata ... basta congelare e rimuovere metodo di spawn, funzionerà .. mi sento confondere quello che hap aiuto ponderato, plz! grazie!

risposta

9

gevent fornisce cooperativo processi leggeri (non thread). La conseguenza è che quando si ha un loop infinito da qualche parte e lo scheduler non viene mai reinserito, il programma bloccherà il 100% del core della CPU.

Nell'esempio, il problema è il modo in cui è stato definito il ciclo del crawler. Ovviamente, hai un ciclo infinito quando le attività sono vuote. E poiché la chiamata gevent.sleep (che eseguirà l'operazione di rendimento necessaria) viene chiamata solo quando le attività non sono vuote, significa che lo scheduler non viene mai reinserito.

Sembra bloccare il comando lpop perché la connessione viene ritardata dal client Redis. La sequenza di eventi è la seguente:

  • il gruppo di attività viene generato; ma nessuna programmata è ancora programmata
  • redis_client è compilato, ma non genera ancora un I/O poiché la connessione effettiva è ritardata
  • lpop viene chiamato; questa volta la connessione è davvero necessaria perché il client Redis deve attendere la connessione e la risposta a lpop; cede quindi alla scheduler
  • lo scheduler attiva un operaio crawler
  • ciclo infinito, dal momento che la coda di compiti è ancora vuota

Se si mette la gevent.sleep() nel ciclo stesso (dopo la se), funzionerà meglio, ma è ancora un modo inefficiente per implementare un dequeuer. Qualcosa del genere sarebbe molto meglio:

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

La get() chiamata blocca il lavoratore, in modo che eviterà il gioco di ping pong tra il lavoratore e il programma di pianificazione, mentre la coda è vuota.

+0

Perché è downvoted? – schlamar

+0

Non lo so, ma resto ancora nella mia risposta ;-) –