Thursday, 21 March 2013

Eventlet snippets

OpenStack services use the green threads model as described here. I found an excellent explanation of Eventlet in a video by Donovan Preston. I have typed in some of the snippets he uses here.




Spawning a green thread


import eventlet
def add(x, y):
return x + y
e = eventlet.spawn(add, 1, 2)
print e
res = e.wait()
print '1 + 2 =', res
view raw spawn.py hosted with ❤ by GitHub
$ python spawn.py
<eventlet.greenthread.GreenThread object at 0xe77870>
1 + 2 = 3

Cooperative yielding


import eventlet
def func1():
# suspend me and run something else
# but switch back to me after 2 seconds (if you can)
eventlet.sleep(2)
print "func1"
def func2():
eventlet.sleep(1)
print "func2"
f1 = eventlet.spawn(func1)
f2 = eventlet.spawn(func2)
f1.wait()
f2.wait()
view raw co-op.py hosted with ❤ by GitHub
$ python co-op.py 
func2
func1

import eventlet
def foo(name):
for i in range(3):
print "foo(%s): i=%d" % (name, i)
eventlet.sleep()
f1 = eventlet.spawn(foo, 'A')
f2 = eventlet.spawn(foo, 'B')
for i in range(3):
print "main: i=%d" % i
eventlet.sleep()
f1.wait()
f2.wait()
view raw interleave.py hosted with ❤ by GitHub
$ python interleave.py 
main:   i=0
foo(A): i=0
foo(B): i=0
main:   i=1
foo(A): i=1
foo(B): i=1
main:   i=2
foo(A): i=2
foo(B): i=2


Not so cooperative


import eventlet
def foo(name):
for i in range(3):
print "foo(%s): i=%d" % (name, i)
f1 = eventlet.spawn(foo, 'A')
f2 = eventlet.spawn(foo, 'B')
for i in range(3):
print "main: i=%d" % i
f1.wait()
f2.wait()
view raw un-co-op.py hosted with ❤ by GitHub

$ python un-co-op.py 
main: i=0
main: i=1
main: i=2
foo(A): i=0
foo(A): i=1
foo(A): i=2
foo(B): i=0
foo(B): i=1
foo(B): i=2

Synchronization queue


import eventlet
q = eventlet.Queue()
def func1():
print "func1", q.get()
def func2():
print "func2", q.get()
waiton = (eventlet.spawn(func1), eventlet.spawn(func2))
q.put("hello")
q.put("world")
for w in waiton:
w.wait()
view raw queue.py hosted with ❤ by GitHub
$ python queue.py 
func1 hello
func2 world

Sychronization event


import eventlet
from eventlet import event
evt = event.Event()
def waiter():
evt.wait()
print "waiter"
w = eventlet.spawn(waiter)
print "sending"
evt.send()
print "sent"
w.wait()
view raw waiter.py hosted with ❤ by GitHub
$ python waiter.py
sending
sent
waiter

import eventlet
from eventlet import event
evt = event.Event()
def waiter():
print "waiter: before wait()"
evt.wait()
print "waiter: after wait()"
w = eventlet.spawn(waiter)
print "main: before send()"
eventlet.sleep()
evt.send()
print "main: after send()"
eventlet.sleep()
print "main: at end"
view raw waiter2.py hosted with ❤ by GitHub
$ python waiter2.py
main: before send()
waiter: before wait()
main: after send()
waiter: after wait()
main: at end


Green pools


import eventlet
pool = eventlet.GreenPool(size=2)
def printer(x):
print x
print "execute 1"
pool.spawn(printer, 1)
print "execute 2"
pool.spawn(printer, 2)
print "execute 3"
pool.spawn(printer, 3)
print "execute 4"
pool.spawn(printer, 4)
pool.waitall()
view raw green_pool.py hosted with ❤ by GitHub
$ python greenpool.py 
execute 1
execute 2
execute 3
1
2
execute 4
3
4

Green sockets


import eventlet
from eventlet.green import socket
def handle_socket(reader, writer):
print "client connected"
while True:
line = reader.readline()
if not line:
break
writer.write(line)
writer.flush()
print "echoed", line.rstrip()
print "disconnected"
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('', 6000))
server.listen(100)
print "server listening on port 6000"
while True:
sock, addr = server.accept()
eventlet.spawn(handle_socket, sock.makefile('r'), sock.makefile('w'))
view raw green_socket.py hosted with ❤ by GitHub
Start the echo server:
$ python greensocket.py
server listening on port 6000

then start another terminal and any lines typed are echoed: 
$ nc localhost 6000
something from client1
something from client1

Now the point is that the program is not blocked handling that socket. So start another terminal:
$ nc localhost 6000
something from client2
something from client2

Then press control-d in each nc to disconnect. The entire server output is:
$ python greensocket.py 
server listening on port 6000
client connected
echoed something from client1
client connected
echoed something from client2
disconnected
disconnected