Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
An Asynchronous, Scalable Django with Twisted (...
Search
Amber Brown (HawkOwl)
June 04, 2016
Programming
220
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
An Asynchronous, Scalable Django with Twisted (PyCon TW 2016 Keynote)
Amber Brown (HawkOwl)
June 04, 2016
More Decks by Amber Brown (HawkOwl)
See All by Amber Brown (HawkOwl)
Batteries Included, But They're Leaking (Python Language Summit, 2019)
hawkowl
0
540
Why Twisted Is The Best (WOOTConf @ LCA 2017)
hawkowl
0
190
Releasing Calendar Versioned Software (PyCon AU 2016)
hawkowl
1
170
Falsehoods Developers Have About Identity (PyCon AU 2016 Lightning Talk)
hawkowl
1
850
The Report of Twisted's Death; or Twisted & Tornado in the Asyncio Age (EuroPython 2016)
hawkowl
0
210
The Report of Twisted's Death; or Twisted & Tornado in the Asyncio Age (PyCon US 2016)
hawkowl
0
250
Twisted & Python 3 (Python Language Summit, 2016)
hawkowl
0
200
The Report of Twisted's Death; or Twisted & Tornado in the Asyncio Age (Perth Django Meetup)
hawkowl
0
220
The Future of Twisted, and Pretty Much Everything Else (PyCon CZ Keynote, 2015)
hawkowl
0
160
Other Decks in Programming
See All in Programming
APNsからLive Activityを開始する話
yumnumm
0
130
AI が書く Go コードの品質を劇的に向上させる Linter: “declscope”
mpyw
0
470
AWSに止められる覚悟してますか?
morizo_1984
2
490
速く作れる。その次は、速く確かめられる開発へ 〜AIネイティブ開発を支える、Shift Down〜 / Can build fast. Next, moving to development where we can verify fast.
rkaga
8
5.3k
Security issues being discussed on Web Platforms
petamoriken
0
1.4k
Unity6 URPによる海底をテーマにしたVJシステムの解説 | Unity Shader 完全に理解した 勉強会
gam0022
0
290
Embedded Swiftで作る自作USBデバイス によるiOSデバイスの自動テスト / iOSDC Japan 2026 glassfiber
glassfiber
0
260
App Intentsのビルドプロセスを支える技術
kntkymt
0
490
iOSDC2026登壇資料.pdf
riofujimon
0
200
KiroのSpecで「五目並べ」を作ってみる
satoshi256kbyte
1
330
半永久的に提供し続けられるプライベートクラウドを目指して ― 利用者の認知負荷を抑えるAPI抽象化とハードウェア世代交代の基盤設計
tomokon
0
390
JAWS-UG 東京支部が始める、JAWS-UG支部コラボ / JAWS-UG lunchtime LT Collaboration
y0hgi
0
170
Featured
See All Featured
Thoughts on Productivity
jonyablonski
76
5.4k
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
550
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
[RailsConf 2023] Rails as a piece of cake
palkan
59
7k
How to train your dragon (web standard)
notwaldorf
97
6.8k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
410
Heart Work Chapter 1 - Part 1
lfama
PRO
10
36k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2.2k
Odyssey Design
rkendrick25
PRO
2
850
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.6k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
Transcript
An Asynchronous, Scalable Django with Twisted
Hello, I’m Amber Brown (HawkOwl)
Twitter: @hawkieowl Pronouns: she/her
I live in Perth, Western Australia
None
Core Developer Release Manager Ported 40KLoC+ to Python 3
None
Binary release management across 3 distros Ported Autobahn|Python (Tx) and
Crossbar.io to Python 3 Web API/REST integration in CB
Scaling Django Applications
Django serves one request at a time
gunicorn, mod_wsgi, etc run multiple copies in threads + processes
Concurrent Requests == processes x threadpool size
nginx gunicorn worker thread thread thread thread gunicorn worker thread
thread thread thread Example server: two workers with four threads each
Need more requests? Add more web servers!
nginx gunicorn worker thread thread thread thread gunicorn worker thread
thread thread thread nginx gunicorn worker thread thread thread thread gunicorn worker thread thread thread thread HAProxy Server 2 Server 3 Server 1
Scaling has required adding a new piece
Higher scale means higher complexity
Is there a better way to handle many requests?
Problem Domain
Modern web applications have two things that take a long
time to do
CPU-bound work Math, natural language processing, other data processing
On most Python interpreters, Python threads are unsuitable for dispatching
CPU-heavy work
Of N Python threads only 1 may run Python code
because of the Global Interpreter Lock
Of N Python threads only N may run C code,
since the Global Interpreter Lock is released
I/O-bound work Database requests, web requests, other network I/O
Threads work better for I/O-bound work
Thread switching overhead is expensive Rapidly acquiring/releasing the GIL is
expensive
First, let's focus on I/O-bound applications.
Asynchronous I/O & Event-Driven Programming
Your code is triggered on events
Events can be: incoming data on the network some computation
is finished a subprocess has ended etc, etc
How do we know when events have occurred?
All events begin from some form of I/O, so we
just wait for that!
Event-driven programming frameworks
Twisted (the project I work on!)
(of SVN history)
asyncio was introduced much later
None
Same at their core, using "selector functions"
select() and friends (poll, epoll, kqueue)
Selector functions take a list of file descriptors (e.g. sockets,
open files) and tell you what is ready for reading or writing
Selector loops can handle thousands of open sockets and events
Data is channeled through a transport to a protocol (e.g.
HTTP, IMAP, SSH)
Sending data is queued until the network is ready
Nothing blocks, it simply gives control to the next event
to be processed
No blocking means no threads
“I/O loops” or “reactors” (as it "reacts" to I/O)
Higher density per core No threads required! Concurrency, not parallelism
Best case: high I/O throughput, high-latency clients, low CPU processing
But what if we need to process CPU bound tasks?
Event Driven Programming with Work Queues
CPU bound tasks are added to a queue, rather than
being ran directly
Web Server Task Queue Worker Worker Worker
We have made the CPU-bound task an I/O-bound one for
our web server
We have also made the scaling characteristics horizontal
Web Server Task Queue Worker Server 2 CPU3 Worker Server
2 CPU2 Worker Server2 CPU1 Worker Server 1 CPU2 Worker Server 1 CPU1 Worker Server 2 CPU4
Putting tasks on the queue and removing them is cheap
Task queues scale rather well
Add more workers to scale!
Do we have an implementation of this?
The Architecture of Django Channels
Project to make an "asynchronous Django"
Authored by Andrew Godwin (behind South, Migrations)
Interface Server Channel Queue Worker Worker Worker Worker Worker Worker
Server 1 Server 2 Server 3 Server 4
Interface server accepts requests, puts them on the Channel (task
queue)
Workers take requests off the Channel and process them
Results from processed requests are written back to the Channel
The interface server picks up these responses and writes it
back out to the HTTP request
The interface server is only I/O bound and does no
"work" of its own
Perfect application for asynchronous I/O!
Daphne, the reference interface server implementation, is written in Twisted
Daphne is capable of handling thousands of requests a second
on modest hardware
The channel layer can be sharded
Channel Queue Server 2 Interface Server Worker Worker Worker Worker
Worker Worker Server 1 Server 4 Server 5 Channel Queue Server 3 (Sharding)
Workers do not need to be on the web server...
but you can put them there if you want!
For small sites, the channel layer can simply be an
Inter- Process-Communication bus
Channel Queue (Shared Memory) Interface Server Worker Worker Worker Server
1
And Twisted understands WebSockets... so can Channels too?
Yep!
How Channels Works
A Channel is where requests are put to be serviced
What is a request? - incoming HTTP requests - connected
WebSocket connection - data on a WebSocket
http.request http.disconnect websocket.connect websocket.receive websocket.disconnect
Your worker listens on these channel names
Information about the request (e.g. a body and headers), and
a "reply channel" identifier
http.response!<client> http.request.body!<client> websocket.send!<client>
http.response!c134x7y http.request.body!c134x7y websocket.send!c134x7y
Reply channels are connection specific so that the correct response
gets to the correct connection
In handling a request, your code calls send() on a
response channel
But because Channels is event-driven, you can't get a "response"
from the event
The workers themselves do not use asynchronous I/O by default!
Under Channels, you write synchronous code, but smaller synchronous code
@receiver(post_save, sender=BlogUpdate) def send_update(sender, instance, **kwargs): Group("liveblog").send({ "id": instance.id, "content":
instance.content, })
Group? What's a group?
Pool of request-specific channels for efficiently sending one-to-many messages
e.g: add all open WebSocket connections to a group that
is notified when your model is saved
Handling different kinds of requests
Workers can listen on specific channels, they don't have to
listen to all of them!
Interface Server Channel Queue Worker Worker Server 1 Server 2
Server 3 (high performance) Server 4 (standard) http.request bigdata.process
Because you can create and listen for arbitrary channels, you
can funnel certain kinds of work into different workers
my_data_set = request.body Channel("bigdata.process").send( {"mydata": my_data_set})
How do we support sending that data down the current
request when it's done?
my_data_set = request.body Channel("bigdata.process").send({ "mydata": my_data_set, "reply_channel": message.reply_channel})
All our big data worker needs to do then is
send the response on the reply channel!
Channels as a bridge to an asynchronous future
A channel doesn't care if you are synchronous or asynchronous
...or written in Django or even Python!
Channels implements "Asynchronous Server Gateway Interface"
The path to a hybrid future Go, Django, Twisted, etc
etc
Channels is due to land in Django 1.11/2.0
Try it out! channels.readthedocs.io
Questions? (pls no statements, save them for after)