## Gevent All The Things
Wes Mason
[@1stvamp](http://twitter.com/1stvamp)
## Who?
- @1stvamp (twitter/github)
- Engineer at [ServerDensity](http://www.serverdensity.com/)
- I release lots of [open source code](http://git.io/1v)
## Gevent
"*[gevent](http://gevent.org/) is a coroutine-based Python networking library that uses greenlet to provide a high-level synchronous API on top of the libevent event loop.*"
## Asynchronous
- [Asynchronous != parallel](http://blog.golang.org/concurrency-is-not-parallelism)
- Non-blocking I/O
- CPU bound vs I/O bound
- Don't mention the War`^W`GIL
## Green threads
- aka Tasklets, micro threads etc.
- Lightweight cooperative "threads"
- Turns coroutines into full switchable "stacks"
- Stackless Python and the `greenlet` module
## What makes Gevent different?
- Implicit event loop
- Synchronous API
- **Monkey patching**
## Out of the box
- Non-blocking sockets, and DNS queries
- SSL support
- TCP server, WSGI server (<1.0.x)
- libevent (now libev)
## WSGI?
- Plug in a Flask app, patch and go
- Multiple instances bound to a single socket/port
### exempli gratia
from gevent.wsgi import WSGIServer
from gevent.socket import tcp_listener
from multiprocessing import Process, cpu_count
from serverdensity.proxy.app import app
def run(app, listener):
http_server = WSGIServer(listener, app)
http_server.serve_forever()
### exempli gratia cont.
listener = tcp_listener(('127.0.0.1', 8000))
for i in xrange((cpu_count() - 1)):
Process(
target=run,
args=(app, listener)
).start()
run(app, listener)
## One Point Oh
- **libev**
- `gevent.subprocess`
- [PyPy](https://github.com/gevent-on-pypy/pypycore)
## Spawning
- `Greenlet` class
- `Greenlet.spawn(c, [...])`
- `greenlet.spawn(c, [...])`
## Flow control
- `gevent.sleep(n)` (yield from)
- `gevent.join(g)`
- `gevent.joinall([...])`
- `greenlet.link(g)`
- `gevent.shutdown`
- Greenlet states
- Timeouts
### exempli gratia
from gevent import spawn, joinall, sleep
def g():
print('foo')
sleep(0)
print('bar')
joinall([spawn(g), spawn(g)])
### exempli gratia cont.
foo
foo
bar
bar
## Data structures
- Events and Queues (like the standard library)
- Groups/Pools/Locks/Semaphores
- Thread locals
## Monkey patching
- `patch_socket()`
- `patch_ssl()`
- `patch_time()`
- `patch_select()`
- `patch_thread()`
- `patch_all()`
## Celery
- Gevent task runner
- Use within processes manually
- **Caution**: defaults ahead
## *NOOP*-ish exempli gratia
# -> HTTP request
mongo.payloads.insert(payloads)
tasks.process_payload.apply_async(payload_id)
# -> celery task (inside a greenlet)
@task
def process_payload(payload_id):
payload = mongo.payloads.findOne({...})
process = PayloadProcessor(payload)
...
return process_alerts.apply_async(payload_id)
### cont.
# inside PayloadProcessor
# (still within a greenlet, controlled by Celery
def send_metrics(self):
payload = copy(self.payload)
# remove some fields we don't want to send,
# turn some to strings
gevent.spawn(self._handle_metrics_request, [payload])
### cont.
def _handle_metrics_request(self, payload):
resp = requests.post(METRICS_URL,
data=json.dumps(payload))
if resp.status_code == 200:
logging.info(...)
return True
else:
logging.error(...)
return False
### deus e.g.
def update_check(self, response):
# update collections in Mongo from response
...
def update_metrics(self):
# send a request to the metrics service
...
def update_inventory(self):
# send a request to the inventory service
...
### deus e.g. cont.
# run from a celery task
def health_check(self):
# get HTTP response from actors
...
update_greenlet = spawn(self.update_check, [response])
update_greenlet.link(spawn(self.update_metrics))
update_greenlet.link(spawn(self.update_inventory))
## Notable mentions
- [grequests](https://github.com/kennethreitz/grequests)
- [geventreactor](https://github.com/jyio/geventreactor)
- [ZeroMQ](https://github.com/traviscline/gevent-zeromq)
## sys.exit(0)
- Code: [git.io/sd](https://github.com/serverdensity), [git.io/1v](https://github.com/1stvamp)
- Slides: [1stvamp.github.com/gevent-talk](http://1stvamp.github.io/gevent-talk)
## ^D
- Jonathan "Joff" Oliver: [about.me/joffie](http://about.me/joffie)
- Grab me and say hi `:-)`