2017-04-08 3 views
0

Zunächst sollte der folgende Code idealerweise die 3 Greenlets synchron laufen lassen, aber stattdessen laufen alle 3 Greenlets asynchron. Das Seltsame ist jedoch, dass es einen zusätzlichen synchronen Prozess für das zweite Greenlet startet, egal wie viele Greenlets Sie haben. Ich stelle diese Frage nicht für eine Problemumgehung, es ist nur, dass ich den Grund dafür verstehen will.Warum die Anzahl der laufenden Greenlets höher ist als die tatsächliche Anzahl der erstellten Greenlets. 1 zusätzliches Greenlet läuft synchron

import gevent 
import time 

def func(i): 
    t = time.time() 
    print('func %s started at %s' % (i, t)) 
    secs = 5 
    statement = "after %s secs" % secs 
    gevent.sleep(secs) 
    print('func %s stopped in %s secs' % (i, (time.time() - t))) 

apps = [gevent.Greenlet.spawn(func, i) for i in range(3)] 

[app.run() for app in apps] 

Hier ist die Probe stdout:

func 0 started at 1491859273.2895772 
func 1 started at 1491859273.2898045 
func 2 started at 1491859273.2899446 
func 0 stopped in 5.0095603466033936 secs 
func 1 started at 1491859278.2993205 
func 1 stopped in 5.0163233280181885 secs 
func 2 stopped in 5.019707918167114 secs 
func 1 stopped in 5.009198188781738 secs 

Wie geschieht func 1 started zweimal?

+0

Könnten Sie über die konkreten Beobachtungen Sie tatsächlich sehen sein expliziter, und wie sie sich unterscheiden von dem, was Sie erwarten: jemals überhaupt genannt wird? (Einige Erklärung von * warum * Sie erwarten, dass die Verhaltensweisen, die Sie tun, auch nicht weh tun würden). –

+0

Ist meine Frage klarer aus den obigen Änderungen? –

+0

Dies hilft insofern, als es eine klare Beschreibung dessen bietet, was Ihr aktuelles Verhalten ist - aber was noch fehlt, ist eine Erklärung, warum Sie ein gegensätzliches/unterschiedliches Verhalten erwarten. –

Antwort

0

Beim Aufruf von spawn() sind bereits Grünlets für den Aufruf geplant. Der direkte Aufruf von run() ist nicht Teil der öffentlich dokumentierten API und die Auswirkungen sind nicht definiert. Jede Beschreibung von warum vorhandenes Verhalten beobachtet wird, müsste dann über die dokumentierte API hinaus in Implementierungsdetails gehen.

Verwenden Sie gevent.joinall(), um auf das Ende Ihrer bereits geplanten Jobs zu warten.

apps = [gevent.Greenlet.spawn(func, i) for i in range(3)] 
gevent.joinall(apps) 

richtig ergibt:

func 0 started at 1491921603.6 
func 1 started at 1491921603.6 
func 2 started at 1491921603.6 
func 0 stopped in 5.00121307373 secs 
func 1 stopped in 5.00118613243 secs 
func 2 stopped in 5.0011780262 secs 

Jetzt wollen wir in diesem undefinierten Verhalten graben ein wenig, mit dem Verständnis, dass es anfällig ist, zu variieren Release-to-release oder System-to-System .

Der Grund, warum es speziell Greenlet 1 ist, das zweimal ausgeführt wird, ist ein Unfall, wenn der primäre Thread der Kontrolle zuerst kooperativ ergibt. Sie können dieses Verhalten ändern, indem run() die ersten Aufruf explizit vor wodurch man

print "=== About to spawn greenlets..." 
apps = [gevent.Greenlet.spawn(func, i) for i in range(3)] 
print "=== All greenlets spawned; yielding..." 
gevent.sleep(0) 
print "=== Calling a duplicate run() invocation on each" 
result = [app.run() for app in apps] 

Mit dieser Änderung ist es greenlet das beginnt erste - und Sie werden bemerken, dass es vorrun() beginnt

=== About to spawn greenlets... 
=== All greenlets spawned; yielding... 
func 0 started at 1491921486.57 
func 1 started at 1491921486.57 
func 2 started at 1491921486.57 
=== Calling a duplicate run() invocation on each 
func 0 started at 1491921486.57 
func 0 stopped in 5.00335502625 secs 
func 1 stopped in 5.00336790085 secs 
func 2 stopped in 5.0033519268 secs 
func 0 stopped in 5.0033428669 secs 
Verwandte Themen