2013-11-04 14 views
15

A seguito della mia domanda nel commento this answer alla domanda "Gevent pool with nested web requests":gevent: lato negativo per generare un gran numero di greenlet?

Ipotizzando uno ha un gran numero di compiti, c'è qualche aspetto negativo di utilizzare gevent.spawn (...) per deporre le uova tutte le porte contemporaneamente piuttosto che usare un gevent pool e pool.spawn (...) per limitare il numero di greenlet concorrenti?

Formulato in modo diverso: esiste un vantaggio per "limitare la concorrenza" con un gevent.Pool anche se non richiesto dal problema da risolvere?

Qualche idea di cosa costituirebbe un "numero elevato" per questo problema?

+0

Quando non si utilizza pool per deporre le uova un gran numero di greenlets, il mio programma continuava alternanza tra due errori: 'gevent.hub.LoopExit: ('Questa operazione bloccherebbe per sempre',' e 'Gevent '. Tutto risolto dopo che ho scoperto una dimensione ottimale del pool per tentativi ed errori. Ancora irrazionale per me, ma noterò come vantaggio di limitare la concorrenza. Inoltre, ho misurato il tempo complessivo impiegato per essere inferiore con 'pool.spawn()' al contrario di 'gevent.spawn()' – Spade

risposta

18

È solo più pulito e una buona pratica quando si tratta di un sacco di cose. Mi sono imbattuto in questo qualche settimana fa stavo usando gevent spawn per verificare un gruppo di email contro DNS nell'ordine di 30k :).

from gevent.pool import Pool 
import logging 
rows = [ ... a large list of stuff ...] 
CONCURRENCY = 200 # run 200 greenlets at once or whatever you want 
pool = Pool(CONCURRENCY) 
count = 0 

def do_work_function(param1,param2): 
    print param1 + param2 

for row in rows: 
    count += 1 # for logging purposes to track progress 
    logging.info(count) 
    pool.spawn(do_work_function,param1,param2) # blocks here when pool size == CONCURRENCY 

pool.join() #blocks here until the last 200 are complete 

ho trovato nella mia prova che quando CONCURRENCY era intorno al 200 è quando il mio carico di macchina avrebbe oscillare intorno 1 su un m1.small EC2. L'ho fatto anche un po 'ingenuamente, se dovessi farlo di nuovo eseguirò più pool e dormirò un po' di tempo tra loro per cercare di distribuire il carico sulla NIC e sulla CPU in modo più uniforme.

Un'ultima cosa da tenere a mente è tenere d'occhio i file aperti e aumentarli se necessario: http://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files. I greenlet che stavo correndo occupavano circa 5 descrittori di file per greenlet, quindi puoi correre abbastanza velocemente se non stai attento. Questo potrebbe non essere utile se il carico del tuo sistema è superiore a uno, poiché inizierai a vedere rendimenti decrescenti a prescindere.

5

Sono venuto qui da Google e ho deciso di eseguire alcuni test rapidi per generare nuovi greenlet N. La condivisione dei risultati in quanto potrebbe essere utile ai colleghi ricercatori:

# 1 greenlet 
real 0m1.032s 
user 0m0.017s 
sys  0m0.009s 

# 100 greenlets 
real 0m1.037s 
user 0m0.021s 
sys  0m0.010s 

# 1,000 greenlets 
real 0m1.045s 
user 0m0.035s 
sys  0m0.013s 

# 10,000 greenlets 
real 0m1.232s 
user 0m0.265s 
sys  0m0.059s 

# 100,000 greenlets 
real 0m3.992s 
user 0m3.201s 
sys  0m0.444s 

Così fino a 1.000 greenlets e la perdita di prestazioni è piccolo, ma una volta che si inizia a colpire 10.000 greenlets, tutto rallenta.

Codice di prova:

import gevent 

N = 0 

def test(): 
    gevent.sleep(1) 

while N < 1000: 
    N += 1 
    gevent.spawn(test) 

gevent.wait() 
Problemi correlati