Skip to content

Commit 43e56e4

Browse files
Move to Jekyll
1 parent 133b52c commit 43e56e4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+12244
-38
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.jekyll-cache
2+
_site

404.html

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1">
7+
<meta name="description" content="Collaboratively funded software development">
8+
<meta name="keywords" content="Open Source, API">
9+
<meta name="author" content="Tom Christie">
10+
11+
<title>Encode</title>
12+
13+
<link href="http://fonts.googleapis.com/css?family=Roboto:100,300,400,700" rel="stylesheet">
14+
<link href="css/toolkit-minimal.css" rel="stylesheet">
15+
<link href="css/application-minimal.css" rel="stylesheet">
16+
<link rel="icon" type="image/png" href="img/icon.png">
17+
18+
<style>
19+
.app-block-intro {padding: 60px 0px}
20+
.block-bordered-lg {padding-top: 50px; padding-bottom: 0px}
21+
.app-block-footer {background: white; padding-bottom: 20px}
22+
</style>
23+
</head>
24+
25+
26+
<body>
27+
28+
<div class="block app-block-intro">
29+
<div class="container text-center">
30+
<h1 class="block-title m-b-sm text-uppercase app-myphone-brand">404</h1>
31+
<p class="lead">Nothing to see here</p>
32+
</div>
33+
</div>
34+
</body>
35+
</html>

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
### Serving the documentation locally
2+
3+
```shell
4+
$ jekyll serve
5+
```

_config.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,12 @@
1-
theme: jekyll-theme-minimal
1+
url: "" # the base hostname & protocol for your site, e.g. http://example.com
2+
baseurl: "" # the subpath of your site, e.g. /blog
3+
title: "Encode" # the name of your site, e.g. ACME Corp.
4+
5+
exclude:
6+
- README.md
7+
8+
plugins:
9+
- jekyll-feed
10+
11+
feed:
12+
path: feeds/articles.rss

_layouts/articles.html

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1">
7+
<meta name="description" content="Collaboratively funded software development">
8+
<meta name="keywords" content="Open Source, API">
9+
<meta name="author" content="Tom Christie">
10+
11+
<title>{{ page.title }} - {{ site.title }}</title>
12+
13+
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,700" rel="stylesheet">
14+
<link href="{{ '/css/toolkit-minimal.css' | relative_url }}" rel="stylesheet">
15+
<link href="{{ '/css/application-minimal.css' | relative_url }}" rel="stylesheet">
16+
<link rel="icon" type="image/png" href="{{ '/img/icon.png' | relative_url }}">
17+
18+
<style>
19+
.app-block-intro {padding: 60px 0px}
20+
.block-bordered-lg {padding-top: 50px; padding-bottom: 0px}
21+
.app-block-footer {background: white; padding-bottom: 20px}
22+
</style>
23+
</head>
24+
25+
26+
<body>
27+
28+
<div class="container" style="margin-bottom: -40px">
29+
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
30+
<div style="float: right">
31+
<ul class="navbar-nav" style="padding-top: 15px">
32+
<li class="nav-item" style="padding: 0 12px; display: block">
33+
<a class="nav-link" href="{{ '/articles/' | relative_url }}">Articles</a>
34+
</li>
35+
<li class="nav-item" style="padding: 0 12px; display: block">
36+
<a class="nav-link" href="{{ '/reports/'| relative_url }}">Reports</a>
37+
</li>
38+
</ul>
39+
</div>
40+
</nav>
41+
</div>
42+
43+
<div class="container">
44+
<h1 id="encode-articles">
45+
<a href="{{ '/' | relative_url }}">Encode</a> / <a href="{{ '/articles/' | relative_url }}">Articles</a> / {{ page.title }}
46+
</h1>
47+
{{ content }}
48+
49+
<hr/>
50+
51+
<div class="block text-center" style="padding-top: 20px">
52+
<div class="container-fluid">
53+
<p class="m-b-md">
54+
Follow all our articles on the <a href="{{ '/feeds/articles.rss' | relative_url }}">RSS feed</a>.
55+
</p>
56+
</div>
57+
</div>
58+
59+
</div>
60+
61+
</body>
62+
</html>

_layouts/default.html

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1">
7+
<meta name="description" content="Collaboratively funded software development">
8+
<meta name="keywords" content="Open Source, API">
9+
<meta name="author" content="Tom Christie">
10+
11+
<title>{{ page.title }} - {{ site.title }}</title>
12+
13+
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,700" rel="stylesheet">
14+
<link href="{{ '/css/toolkit-minimal.css' | relative_url }}" rel="stylesheet">
15+
<link href="{{ '/css/application-minimal.css' | relative_url }}" rel="stylesheet">
16+
<link rel="icon" type="image/png" href="{{ '/img/icon.png' | relative_url }}">
17+
18+
<style>
19+
.app-block-intro {padding: 60px 0px}
20+
.block-bordered-lg {padding-top: 50px; padding-bottom: 0px}
21+
.app-block-footer {background: white; padding-bottom: 20px}
22+
</style>
23+
</head>
24+
25+
26+
<body>
27+
28+
<div class="container" style="margin-bottom: -40px">
29+
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
30+
<div style="float: right">
31+
<ul class="navbar-nav" style="padding-top: 15px">
32+
<li class="nav-item" style="padding: 0 12px; display: block">
33+
<a class="nav-link" href="{{ '/articles/' | relative_url }}">Articles</a>
34+
</li>
35+
<li class="nav-item" style="padding: 0 12px; display: block">
36+
<a class="nav-link" href="{{ '/reports/'| relative_url }}">Reports</a>
37+
</li>
38+
</ul>
39+
</div>
40+
</nav>
41+
</div>
42+
43+
<div class="container">
44+
{{ content }}
45+
</div>
46+
47+
</body>
48+
</html>

_layouts/reports.html

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1">
7+
<meta name="description" content="Collaboratively funded software development">
8+
<meta name="keywords" content="Open Source, API">
9+
<meta name="author" content="Tom Christie">
10+
11+
<title>{{ page.title }} - {{ site.title }}</title>
12+
13+
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,700" rel="stylesheet">
14+
<link href="{{ '/css/toolkit-minimal.css' | relative_url }}" rel="stylesheet">
15+
<link href="{{ '/css/application-minimal.css' | relative_url }}" rel="stylesheet">
16+
<link rel="icon" type="image/png" href="{{ '/img/icon.png' | relative_url }}">
17+
18+
<style>
19+
.app-block-intro {padding: 60px 0px}
20+
.block-bordered-lg {padding-top: 50px; padding-bottom: 0px}
21+
.app-block-footer {background: white; padding-bottom: 20px}
22+
</style>
23+
</head>
24+
25+
26+
<body>
27+
28+
<div class="container" style="margin-bottom: -40px">
29+
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
30+
<div style="float: right">
31+
<ul class="navbar-nav" style="padding-top: 15px">
32+
<li class="nav-item" style="padding: 0 12px; display: block">
33+
<a class="nav-link" href="{{ '/articles/' | relative_url }}">Articles</a>
34+
</li>
35+
<li class="nav-item" style="padding: 0 12px; display: block">
36+
<a class="nav-link" href="{{ '/reports/'| relative_url }}">Reports</a>
37+
</li>
38+
</ul>
39+
</div>
40+
</nav>
41+
</div>
42+
43+
<div class="container">
44+
<h1 id="encode-articles">
45+
<a href="{{ '/' | relative_url }}">Encode</a> / <a href="{{ '/reports/' | relative_url }}">Monthly Reports</a> / {{ page.title }}
46+
</h1>
47+
{{ content }}
48+
</div>
49+
50+
</body>
51+
</html>

_posts/2018-10-08-hello-asgi.md

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
---
2+
layout: articles
3+
title: "Hello, ASGI"
4+
permalink: "/articles/hello-asgi"
5+
---
6+
7+
*This article offers an introduction to the emerging [ASGI standard](https://asgi.readthedocs.io/en/latest/), and what benefits it provides to Python web frameworks.*
8+
9+
One of the newest changes in the current Python landscape is a focus on asynchronous programming models, with the introduction of `async`/`await` syntax into the language.
10+
11+
The asynchronous model uses lightweight task-based switching, with explicit switch points and flow control managed within the runtime. This is in contrast to thread-based concurrency, which is more resource intensive, and relies on implicit switching, managed by the operating system.
12+
13+
More modern runtimes such as Go and Node are based on asynchronous models. As a relatively old language, Python is having to adapt to it incrementally, which presents both opportunities and challenges.
14+
15+
One of these challenges is in how Python web frameworks can adapt to the potential benefits of an asynchronous model. We've seen this with a recent influx of [high performing](https://www.starlette.io) [Python](https://sanic.readthedocs.io/en/latest/) [web](https://vibora.io/) [frameworks](https://github.com/squeaky-pl/japronto).
16+
17+
## A review of WSGI
18+
19+
The long-standing web frameworks of the Python landscape, including Django, Flask, Falcon, Pyramid, and Bottle are all WSGI-based frameworks.
20+
21+
WSGI is a standard that provides a formalized interface between the Server implementation, that deals with the nitty-gritty details of the raw socket handling, and the Application implementation.
22+
23+
Having a formalized interface here is hugely important, as it provides a proper separation of concerns between these two aspects, and allows server implementations to evolve independently of framework or application implementations.
24+
25+
Python has a number of WSGI servers, including [Gunicorn](https://gunicorn.org/), [uWSGI](https://uwsgi-docs.readthedocs.io/en/latest/), [Apache/mod_wsgi](https://modwsgi.readthedocs.io/en/develop/), and [Waitress](https://docs.pylonsproject.org/projects/waitress/en/latest/).
26+
27+
I'm not going to delve into the specifics of the WSGI interface in this article, but we'll can take a quick look at running a basic "Hello, world" web service:
28+
29+
**example.py**:
30+
31+
```python
32+
def hello_world(environ, start_response):
33+
data = b"Hello, World!\n"
34+
start_response("200 OK", [
35+
("Content-Type", "text/plain"),
36+
])
37+
return [data]
38+
```
39+
40+
We can now run our hello world application with any WSGI server:
41+
42+
```shell
43+
$ gunicorn example:hello_world
44+
```
45+
46+
WSGI has been hugely successful, and it's near-universal adoption is testament to the importance of a server/application interface, but it comes with a couple of constraints that are not easily overcome without a significant overhaul.
47+
48+
For one thing, WSGI is necessarily a thread-based or greenlet based interface, and *cannot* support an `async`/`await` model. WSGI is inherently not able to take advantage of the potential benefits of asynchronous programming.
49+
50+
For another thing, WSGI is strictly an HTTP interface, and cannot easily be adapted to provide support for WebSockets or other network protocols.
51+
52+
## Enter ASGI
53+
54+
This is where ASGI comes in.
55+
56+
[The ASGI specification](https://asgi.readthedocs.io/) is an iterative but fundamental redesign, that provides an async server/application interface, with support for HTTP, HTTP/2, and WebSockets.
57+
58+
For contrast, here's an example of an ASGI "Hello, World" service.
59+
60+
**example.py**:
61+
62+
```python
63+
class HelloWorld:
64+
def __init__(self, scope):
65+
pass
66+
67+
async def __call__(self, receive, send):
68+
await send({
69+
'type': 'http.response.start',
70+
'status': 200,
71+
'headers': [
72+
[b'content-type', b'text/plain'],
73+
]
74+
})
75+
await send({
76+
'type': 'http.response.body',
77+
'body': b'Hello, world!',
78+
})
79+
```
80+
81+
We can run our example by installing an ASGI server. In this case, using [uvicorn](https://www.uvicorn.org/):
82+
83+
```shell
84+
$ uvicorn example:HelloWorld
85+
```
86+
87+
Again, I won't go into the specifics of the specification in this article, but two key things to note in the interface are:
88+
89+
* The `async` syntax in the `__call__` method, which explicitly marks it as a possible point of task-switches, and allows other asynchronous code to be used within that execution context.
90+
* The `receive` and `send` parameters, over which the messaging between the server and application takes place.
91+
92+
This async/await based interface has a number of advantages over WSGI.
93+
94+
### Performance characteristics
95+
96+
Async code is able to attain *significantly* higher throughput than thread-based concurrency in cases where code is primarily network-bound, rather than compute-bound. The resource efficient switching of task-based concurrency means that thousands of lightweight tasks can be executed alongside each other, without the high overhead of thread-based switching. This means that each single server or instance is able to support a *far* larger volume of traffic.
97+
98+
Python frameworks have historically been a poor candidate for certain classes of use-case where asynchronous runtimes such as Node or Go have excelled.
99+
100+
The ASGI specification provides an opportunity for Python to hit a productivity/performance sweet-spot for a wide range of use-cases, from writing high-volume proxy servers through to bringing large-scale web applications to market at speed.
101+
102+
For example, here's the [latest suite of results](https://www.techempower.com/benchmarks/#section=test&runid=14a815b6-93c1-4207-96bb-3960c29719e2&hw=ph&test=fortune&l=zij5z3-1&d=e3) from the TechEmpower benchmarks, filtered down to a few dynamic languages (Python, JavaScript, Ruby, PHP, Perl) all using a Postgres backend:
103+
104+
![TechEmpower benchmarks](/img/asgi-performance.png)
105+
106+
With Starlette and Uvicorn towards the top of the list, Python comes out of those benchmarks with comparable performance characteristics to Node.
107+
108+
### Support for WebSockets and long-lived HTTP connections
109+
110+
ASGI directly supports WebSockets, allowing developers to build more responsive web applications, and other highly interactive services that are not well suited to HTTP.
111+
112+
It can also used to support HTTP long-polling, or HTTP Server Sent Events, which allows for uni-directional server-to-client updates.
113+
114+
### Support for HTTP/2
115+
116+
ASGI is able to [support HTTP/2 server-push](https://asgi.readthedocs.io/en/latest/extensions.html#http-2-server-push), allowing frameworks to preemptively send additional media to the client when a page load is performed. This be can used to achieve lower latencies for websites that are able to avoid some of the required roundtrips that characterize the loading of a webpage over HTTP/1.1.
117+
118+
### In-process background tasks
119+
120+
The messaging model that ASGI provides means that it is able to continue to run code after the HTTP response has been sent. This allows frameworks to provide lightweight in-process background tasks, without the need for infrastructure to support a full-blown task queue.
121+
122+
### Extensibility
123+
124+
Where WSGI presents an interface of "call into this function with an HTTP request, and wait until an HTTP response is returned", the ASGI specification presents a more broadly extensible interface of "here's a pair of channels between which the server and application can communicate".
125+
126+
This more general pattern has the potential to be extended into other protocols beyond HTTP or WebSockets.
127+
128+
## Where are we now?
129+
130+
There are a number of production-ready ASGI servers:
131+
132+
* `daphne` - The original ASGI server. Originally developed for Django channels.
133+
* `uvicorn` - A high performance ASGI server, with an implementation based on [uvloop](https://github.com/MagicStack/uvloop) and [httptools](https://github.com/MagicStack/httptools).
134+
* `hypercorn` - A fully-featured ASGI server, including support for features such as HTTP/2 server push.
135+
136+
Each of these has a measure of established production-use, and all three have helped inform the refinement of the ASGI specification.
137+
138+
There are also a few different ASGI frameworks.
139+
140+
* `channels` - Django's answer to WebSocket support. Provides a thread-based application context over an async-based server implementation.
141+
* `starlette` - Starlette is designed to be used either as a fully featured Web framework, or a toolkit for working with ASGI. A high performance framework with a feature-set that is similar in scope to Sanic or Werkzeug.
142+
* `quart` - A Python ASGI web micro-framework with the same API as Flask.
143+
144+
ASGI also provides a manageable upgrade path for existing web frameworks to provide async support, since it [maps well onto WSGI](https://asgi.readthedocs.io/en/latest/specs/www.html#wsgi-compatibility) while adding additional capabilities.
145+
146+
There are positive noises [from the maintainers of Werkzeug/Flask](https://github.com/pallets/werkzeug/issues/1322), and from [the Falcon team](https://github.com/falconry/falcon/issues/1358). There's also been consideration from the Django team about [bringing ASGI support into the core framework](https://groups.google.com/d/msg/django-developers/Kw7-xV6TrSM/dfD_E4R5AQAJ).
147+
148+
There is also tentative support from maintainers of some asyncio-based frameworks, [including Sanic](https://github.com/huge-success/sanic/pull/1265#issuecomment-424080771).
149+
150+
## Continuing this series
151+
152+
My development work here is focused on [the ASGI server, Uvicorn](https://www.uvicorn.org/), and [the ASGI framework, Starlette](https://www.starlette.io).
153+
154+
Over the coming weeks I'll be writing in more detail about working with ASGI, including how to use it to build WebSocket-based applications, HTTP proxy servers, ASGI middleware, and more.
155+
156+
Our next article will start looking in more detail at [working with HTTP in ASGI](asgi-http).
157+
158+
<p style="float: right">&mdash; <a href="https://twitter.com/_tomchristie">Tom Christie on Twitter</a> | <a href="https://www.encode.io/feeds/articles.rss">RSS feed<a/></p>

0 commit comments

Comments
 (0)