real-time python web: gevent and socket.io

27
© 2011Geeknet Inc Real-Time Web: Gevent and Socket.io Rick Copeland @rick446 [email protected]

Upload: rick-copeland

Post on 08-May-2015

19.985 views

Category:

Technology


3 download

TRANSCRIPT

Page 1: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

Real-Time Web: Gevent and Socket.io

Rick Copeland@rick446

[email protected]

Page 2: Real-Time Python Web: Gevent and Socket.io

- Getting started with Gevent

- AJAX, push, WebSockets, wha?

- ZeroMQ for fun and multiprocessing

- Putting it all together

Page 3: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

A (very) Brief Survey of Python Asynchronous Programming

AsynCore In stdlib, used for stdlib SMTP server Nobody cares about it anymore

Twisted Large community, vast amounts of code Callbacks hurt my brain

Stackless Cool, cooperative multithreading Needs a custom Python

Event-based green threads Like stackless, but in regular Python Know when you yield

Page 4: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

Let’s Go Green: Async that Doesn’t Hurt Your Brain

Greenlets: Cooperative, lightweight threads

Very forgiving – mutexes rarely needed

Use it for IO!

Page 5: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

Gevent: Greenlets

Spawn helpers spawn(my_python_function, *args, **kwargs) Also spawn_later(), spawn_link(), etc.

Greenlet class Like threads but cooperative Useful properties: .get(), .join(), .kill(), .link()

Timeouts Timeout(seconds, exception).start()

Pools: for limiting concurrency, use Pool.spawn

Page 6: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

Gevent: Communication

Event set() clear() wait()

Queue Modeled after Queue.Queue .get() .put() __iter__() PriorityQueue, LifoQueue, JoinableQueue

Page 7: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

Gevent: Networking

“Green” versions of sockets, select(), ssl, and dns Quick and dirty:

import gevent.monkey

gevent.monkey.patch_all()

Page 8: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

Gevent: Servers

Simple callback interface Creates one greenlet per connection (but remember,

that’s OK!)

def handle(socket, address):

print 'new connection!’

server = StreamServer(

('127.0.0.1', 1234), handle)

# creates a new server

server.start()

# start accepting new connections

Page 9: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

Gevent: WSGI

gevent.wsgi Fast (~4k requests/s) No streaming, pipelining, or ssl

gevent.pywsgi: Full featured Slower (“only” 3k requests/s)

from gevent import pywsgi

def hello_world(env, start_response):

start_response('200 OK', [('Content-Type', 'text/html')])

yield '<b>Hello world</b>’

server = pywsgi.WSGIServer(

('0.0.0.0', 8080), hello_world)

server.serve_forever()

Page 10: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

- Getting started with Gevent

- AJAX, push, WebSockets, wha?

- ZeroMQ for fun and multiprocessing

- Putting it all together

Page 11: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

What is the real-time web? No page refreshes

Server push

Examples: chat, realtime analytics, …

Implementation Flash (eww…) Polling (2x eww…) Long polling (wow – that’s clever :-/ ) HTML5 WebSockets (Super-easy! Awesome! Security

vulnerabilities! Immature spec!)

Page 12: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

SocketIO to the Rescue

“Socket.IO aims to make realtime apps possible in every

browser and mobile device, blurring the differences

between the different transport mechanisms.”

Page 13: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

Socket.io Example

<script src="/socket.io/socket.io.js"></script><script> var socket = io.connect('http://localhost'); socket.on('news', function (data) { console.log(data); socket.emit('my other event’, { my:'data' }); });</script>

Page 14: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

gevent_socketio

def hello_world(environ, start_response): if not environ['PATH_INFO'].startswith( '/socket.io'): return serve_file(environ, start_response) socketio = environ['socketio'] while True: socketio.send('Hello, world') gevent.sleep(2)

Page 15: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

- Getting started with Gevent

- AJAX, push, WebSockets, wha?

- ZeroMQ for fun and multiprocessing

- Putting it all together

Page 16: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

ZeroMQ Overview

C library with Python bindings

ZMQ “sockets” are message based, delivery is via a dedicated communication thread

ZMQ transports (tcp, inproc, unix, multicast)

ZMQ socket types REQ/RES PUSH/PULL PUB/SUB …

Page 17: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

pyzmq and gevent_zmq

pyzmq works great for threading

gevent_zmq is necessary for gevent (single-threaded)

Be careful when forking or otherwise using multiprocessing!

Gevent has a global “hub” of greenlets ZeroMQ has a global thread & “context” for communication Best to wait till done forking before initializing ZeroMQ

Page 18: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

ZeroMQ: bind/connect and pub/sub

from gevent_zeromq import zmq

context = zmq.Context()

sock_queue = context.socket(zmq.PUB)

sock_queue.bind('inproc://chat')

zmq_sock = context.socket(zmq.SUB)

zmq_sock.setsockopt(zmq.SUBSCRIBE, "")

zmq_sock.connect('inproc://chat')

Page 19: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

- Getting started with Gevent

- AJAX, push, WebSockets, wha?

- ZeroMQ for fun and multiprocessing

- Putting it all together

Page 20: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

WebChat: Design

IncomingGreenlet

ZMQ send

OutgoingGreenlet

Socket.io

ZMQ recv

JSON Messages JSON Messages

Socket.io

Page 21: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

WebChat: HTML

<h1>Socket.io Chatterbox</h1><div id="status" style="border:1px solid black;"> Disconnected</div><form> <input id="input" style="width: 35em;"></form><div id="data" style="border:1px solid black;"></div><script src="/js/jquery.min.js"></script><script src="/js/socket.io.js"></script><script src="/js/test.js"></script>

Page 22: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

WebChat: JavascriptSetup

(function() { // Create and connect socket var socket = new io.Socket('localhost'); socket.connect(); // Socket status var $status = $('#status'); socket.on('connect', function() { $status.html('<b>Connected: ' + socket.transport.type + '</b>'); }); socket.on('error', function() { $status.html('<b>Error</b>'); }); socket.on('disconnect', function() { $status.html('<b>Closed</b>'); });

Page 23: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

WebChat: JavascriptCommunication

// Send data to the server var $form = $('form'); var $input = $('#input'); $form.bind('submit', function() { socket.send($input.val()); $input.val(''); return false; }); // Get data back from the server var $data = $('#data'); socket.on('message', function(msg) { msg = $.parseJSON(msg); var u = msg.u || 'SYSTEM’; $data.prepend($( '<em>' + u + '</em>: ' + msg.m + '<br/>')); });})();

Page 24: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

WebChat: Server

def chat(environ, start_response): if not environ['PATH_INFO'].startswith( '/socket.io): return serve_file(environ, start_response) socketio = environ['socketio'] #... handle auth ... zmq_sock = context.socket(zmq.SUB) zmq_sock.setsockopt(zmq.SUBSCRIBE, "") zmq_sock.connect('inproc://chat') greenlets = [ gevent.spawn(incoming, uname, socketio), gevent.spawn(outgoing, zmq_sock, socketio) ] gevent.joinall(greenlets)

Page 25: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

WebChat: Greenlets

def incoming(uname, socketio): while True: for part in socketio.recv(): sock_queue.send(json.dumps(dict( u=uname, m=part)))

def outgoing(zmq_sock, socketio): while True: socketio.send(zmq_sock.recv())

Page 26: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

Get the Code!

Socket.iohttp://socket.ioMIT License

Chatterboxhttp://sf.net/u/rick446/

pygothamApache License

ZeroMQhttp://www.zeromq.org

LGPL License

Geventhttp://gevent.org

MIT License

Page 27: Real-Time Python Web: Gevent and Socket.io

© 2011Geeknet Inc

Rick Copeland@rick446

[email protected]