Communication in 
Python and the 
C10k problem 
Jose Ignacio Galarza 
@igalarzab
MANOLOOOOO!!!!
select the best 
method to 
communicate
select the best 
method to 
scale
Index 
✤ From polling… to pushing 
✤ Concurrency 
✤ C10k 
✤ Asynchronous I/O
PYTHON 3 
PYTHON 3 EVERYWHERE
From polling 
to pushing
polling 
Client Server
polling 
➡ Nothing new to implement 
➡ Good support in all platforms 
➡ Proxy friendly 
➡ Uni-directional 
➡ Very low efficiency 
➡ No cross-domain
@app.route("/messages") 
def messages(): 
message = check_new_message() 
return message 
while True: 
polling 
r = requests.get('http://api.yo.com/messages') 
messages.extend(r.json()) 
time.sleep(5)
long polling 
Client Server
long polling 
➡ Good support in all platforms 
➡ “Proxy friendly” 
➡ Uni-directional 
➡ Low efficiency (better than polling) 
➡ No cross-domain
long polling 
@app.route("/messages") 
def messages(): 
message = wait_until_new_message() 
return message 
while True: 
try: 
r = requests.get('http://yo.com/messages', timeout=60) 
except TimeOut: 
continue 
messages.extend(r.json())
HTTP Streaming 
Client Server
HTTP Streaming 
➡ Better efficiency than (long) polling 
➡ “Proxy friendly” 
➡ Uni-directional 
➡ You need to parse the data manually
HTTP Streaming 
➡ Type 1: Connection Close 
HTTP/1.1 200 OK 
Content-Type: text/plain 
Connection: close 
Hello world 
This a connection close response
HTTP Streaming 
➡ Type 2: Chunked response 
HTTP/1.1 200 OK 
Content-Type: text/plain 
Transfer-Encoding: chunked 
E 
Hello World! 
19 
I am a chunked response 
0
HTTP Streaming 
@app.route("/messages") 
def messages(): 
def content(): 
for sentence in wait_until_next_sentence(): 
yield sentence 
return Response(content()) 
r = requests.get('http://yo.com/messages', stream=True) 
for message in r.iter_lines(): 
messages.extend(message.decode(‘utf8’))
SSE 
Client Server
SSE 
➡ Well known protocol (HTTP) 
➡ Good efficiency 
➡ JS API 
➡ Few client implementations 
➡ Uni-directional
WebSockets 
Client Server
WebSockets 
➡ Bidirectional 
➡ Great efficiency 
➡ A lot of implementations (JS API) 
➡ Cross-domain 
➡ Handshake to update from HTTP 
➡ Complete different protocol
WS Handshake 
GET /chat HTTP/1.1 
Host: server.example.com 
Upgrade: websocket 
Connection: Upgrade 
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== 
Sec-WebSocket-Protocol: chat, superchat 
Sec-WebSocket-Version: 13 
Origin: http://example.com 
HTTP/1.1 101 Switching Protocols 
Upgrade: websocket 
Connection: Upgrade 
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= 
Sec-WebSocket-Protocol: chat 
Wikipedia
WebSockets 
@sockets.route('/messages') 
def messages(ws): 
while True: 
message = wait_until_new_message() 
ws.send(message) 
def msg(ws, msg): 
messages.extend(msg) 
ws = websocket.WebSocketApp(‘ws://api.yo.com/', on_message=msg) 
ws.on_open = on_open 
ws.run_forever()
Bytes IN Bytes Out Total Bytes Time (seconds) 
Polling 14640 13564 28204 159 
Polling 2 7503 7636 15139 200 
Long Polling 7503 7636 15139 120 
Streaming 183 1549 1732 120 
WebSockets 209 1605 1814 120
30000 
27000 
24000 
21000 
18000 
15000 
12000 
9000 
6000 
3000 
0 
Polling 
Polling 2 
Long Polling 
Streaming 
WebSockets 
Total Bytes Bytes Out Bytes IN
Concurrency 
and the 
C10k
C1 
0k? 
how to handle more than 
10k connections 
simultaneously?
concurrency is… 
the ability of running in 
overlapping time periods, 
not necessarily at the 
same time
concurrency 
!= 
parallelism
processes 
➡ Preemptive scheduling by the OS 
➡ Separate memory space 
➡ No GIL related issues 
➡ How to communicate them? 
➡ They are really heavy
threads 
➡ Preemptive scheduling by the OS 
➡ Same memory space 
➡ Faster and lighter than processes 
➡ You may suffer the GIL 
➡ What about synchronisation? 
➡ Race conditions
user threads 
➡ Same space address 
➡ Lightest alternative 
➡ No race-conditions 
➡ You may suffer the GIL 
➡ Very bad with CPU bound tasks
GIL
I/O 
methods
again… 
how to handle more than 
10k connections 
simultaneously?
option 1 
use 10k machines, one per 
client, VIP service
option 2 
use blocking and 
synchronous calls, 
one per client
option 3 
non-blocking calls to start 
I/O and then readiness 
notifications to know 
when the socket 
is ready
option 4 
asynchronous calls to 
start I/O and completion 
notifications to know 
when they’ve finished
but… 
in Python?
twisted 
tornado 
gevent
asyncio 
(aka tulip)
asyncio 
➡ Single-threaded 
➡ Async I/O 
➡ Coroutines 
➡ Multiplexes I/O events 
➡ …
COROUTINES
asyncio 
websockets
demo
X 
Game Of Life
10K 
connections
questions? 
@igalarzab
thanks!

Communication in Python and the C10k problem