Halo, Habr! Saya mempersembahkan kepada Anda terjemahan artikel "Pengantar ASGI: Munculnya Async Python Web Ecosystem" oleh Florimond Manca.

"Turtles Near The Pond," Ricard Baraham di unsplash.com
Python tidak terbatas pada Ilmu Data, pengembangan web Python telah kembali dengan giliran asinkron baru dalam pengembangan bahasa!
Banyak peristiwa penting yang terjadi di ekosistem pengembangan web Python. Salah satu penggerak utama dari perubahan ini adalah ASGI - Asynchronous Standard Gateway Interface.
Saya telah menyebutkan ASGI beberapa kali di blog saya, khususnya, ketika saya mengumumkan Bocadillo ( kerangka kerja web Python open-source asinkron - kira-kira Per . ) Dan tartiflette-starlette ( pustaka untuk membangun GraphQL API melalui HTTP melalui ASGI - kira-kira. . ), tapi saya tidak pernah menulis pengantar terperinci tentang dia. Sekarang saya akan melakukannya.
Artikel ini ditujukan untuk orang yang tertarik dengan tren terbaru dalam pengembangan web Python. Saya ingin mengajak Anda bertamasya dari mana Anda akan belajar apa ASGI itu dan apa artinya bagi pengembangan web modern di dunia Python.
Sebelum kita mulai, saya ingin memberi tahu Anda bahwa saya baru saja membuat awesome-asgi - daftar hebat untuk melacak ekosistem ASGI yang terus berkembang.
Semuanya dimulai dengan async / menunggu
Tidak seperti JavaScript atau Go, pada saat kemunculannya, Python tidak memberikan kemampuan untuk mengeksekusi kode secara tidak sinkron. Untuk waktu yang lama, eksekusi kode paralel di Python hanya dapat direalisasikan dengan bantuan multithreaded atau multiprocessing, atau menggunakan pustaka jaringan khusus seperti eventlet, gevent atau Twisted. (Kembali pada 2008, Twisted memiliki API untuk coroutine asinkron, misalnya, dalam bentuk inlineCallbacks
dan deferredGenerator
)
Semuanya telah berubah dalam Python 3.4+. Dalam Python 3.4, asyncio dimasukkan dalam perpustakaan standar, menghasilkan dukungan untuk multitasking kooperatif berdasarkan generator dan yield from
sintaksis.
Kemudian dalam Python 3.5 , sintaks async/await
ditambahkan . Berkat ini, coroutine asli muncul, terlepas dari implementasi yang mendasari, yang menyebabkan demam emas di sekitar concurrency di Python.
Perlombaan gila telah dimulai! Sejak rilis versi 3.5, komunitas telah benar-benar menyinkronkan semua yang ada di sekitarnya. Jika Anda tertarik, banyak proyek yang dihasilkan terdaftar dalam aio-libs dan awesome-asyncio .
Seperti yang Anda duga, ini juga berarti bahwa server web dan aplikasi Python bergerak ke arah sinkronisasi. Faktanya, semua pria keren melakukannya! ( Even Django ) ( Habr: Django 3.0 akan asinkron , sudah dirilis pada 12/02/2019 - kira-kira. )
Ulasan ASGI
Jadi bagaimana ASGI cocok dengan semua ini?
ASGI tingkat atas dapat dianggap sebagai tautan yang memungkinkan server dan aplikasi Python asinkron berinteraksi satu sama lain. Dia mengulangi banyak ide arsitektur dari WSGI , dan sering disajikan sebagai penggantinya dengan built-in asynchrony.
Ini adalah bagaimana itu dapat diwakili pada diagram:

Pada tingkat yang sangat tinggi, ASGI adalah antarmuka untuk komunikasi antara aplikasi dan server. Namun pada kenyataannya, semuanya sedikit lebih rumit.
Untuk memahami bagaimana ASGI benar-benar bekerja, mari kita lihat spesifikasi ASGI .
ASGI terdiri dari dua komponen berbeda:
- Protokol Server - mendengarkan pada soket dan mengubahnya menjadi koneksi dan pesan acara dalam setiap koneksi.
- Sebuah aplikasi ( aplikasi ), yang hidup di dalam server protokol, instance-nya dibuat satu kali untuk setiap koneksi dan memproses pesan-pesan event ketika terjadi.
Dengan demikian, sesuai dengan spesifikasi, apa yang sebenarnya ditunjukkan ASGI adalah format pesan dan bagaimana pesan-pesan ini harus ditransfer antara aplikasi dan server protokol yang menjalankannya.
Sekarang kita dapat membuat versi diagram yang lebih rinci:

Ada banyak detail lebih menarik dalam protokol. Misalnya, Anda dapat melihat spesifikasi HTTP dan WebSocket .
Selain itu, meskipun spesifikasinya sangat terfokus pada interaksi antara server dan aplikasi, ASGI berhasil mencakup lebih banyak aspek.
Kita sampai dalam satu menit, tapi pertama ...
ASGI Basics
Sekarang kita telah melihat bagaimana ASGI masuk ke ekosistem web Python, mari kita lihat lebih dekat bagaimana ini diterjemahkan ke dalam kode.
ASGI bergantung pada model sederhana: ketika klien terhubung ke server, instance aplikasi dibuat. Kemudian data yang masuk ditransfer ke aplikasi dan semua data yang dikembalikan dikirim kembali.
Mengirim data ke aplikasi di sini sebenarnya berarti memanggil aplikasi seolah-olah itu adalah fungsi, mis. sesuatu yang mengambil input dan mengembalikan output.
Faktanya, semua yang diwakili oleh aplikasi ASGI adalah callable (disebut objek). Parameter objek yang disebut ini, sekali lagi, ditentukan oleh spesifikasi ASGI :
async def app(scope, receive, send): ...
Tanda tangan dari fungsi ini adalah persis apa yang berarti "I" dalam "ASGI": antarmuka yang harus diimplementasikan aplikasi agar server dapat memanggilnya.
Mari kita lihat parameter fungsi:
scope
adalah kamus yang berisi informasi tentang permintaan yang masuk. Isinya berbeda untuk koneksi HTTP dan WebSocket .- accept adalah fungsi asinkron untuk menerima pesan tentang peristiwa ASGI.
send
adalah fungsi asinkron untuk mengirim pesan tentang peristiwa ASGI.
Bahkan, parameter ini memungkinkan Anda untuk menerima ( receive()
) dan mengirimkan ( send()
) data melalui saluran komunikasi yang didukung oleh server protokol, serta memahami dalam konteks (atau scope
) saluran mana yang dibuat saluran ini.
Saya tidak tahu tentang Anda, tetapi saya sangat suka tampilan umum dan struktur antarmuka ini. Bagaimanapun, sekarang mari kita lihat kode sampel.
Tunjukkan kodenya!
Untuk mendapatkan gambaran praktis seperti apa ASGI itu, saya membuat proyek minimal pada ASGI telanjang yang menunjukkan aplikasi HTTP yang dilayani oleh uvicorn (server ASGI populer):
async def app(scope, receive, send): assert scope["type"] == "http" await send({ "type": "http.response.start", "status": 200, "headers": [ [b"content-type", b"text/plain"], ] }) await send({ "type": "http.response.body", "body": b"Hello, world!", })
Kode sumber - https://glitch.com/edit/#!/asgi-hello-world
Di sini kami menggunakan send()
untuk mengirim respons HTTP ke klien: pertama kami mengirim header, dan kemudian badan respons.
Saya akui bahwa karena semua kamus dan data biner mentah ini, ASGI telanjang tidak nyaman untuk bekerja.
Untungnya, ada opsi tingkat yang lebih tinggi - dan saat itulah saya mulai berbicara tentang Starlette .
Starlette adalah proyek yang benar-benar fantastis, dan, menurut pendapat saya, merupakan bagian mendasar dari ekosistem ASGI.
Secara singkat, ini menyediakan satu set komponen tingkat tinggi, seperti permintaan dan jawaban, yang dapat Anda gunakan untuk abstrak dari beberapa detail ASGI. Di sini, lihat "hello world" di Starlette:
Starlette memiliki semua yang Anda harapkan dari kerangka kerja nyata - perutean, middleware, dll. Tapi saya memutuskan untuk menunjukkan versi ini untuk mengisyaratkan kekuatan ASGI yang sebenarnya, yaitu ...
Kura-kura sepanjang jalan
Konsep yang menarik dan mengubah aturan untuk ASGI adalah Turtles All the Way , sebuah ekspresi yang awalnya diciptakan (menurut saya?) Oleh Andrew Godwin, yang menciptakan Django Migrations dan saat ini sedang mengerjakan Django untuk mendukung asynchrony .
Tapi apa sebenarnya artinya ini?
Karena ASGI adalah abstraksi yang memungkinkan kita untuk mengatakan dalam konteks apa kita berada dan untuk menerima dan mengirim data kapan saja, ada ide bahwa ASGI dapat digunakan tidak hanya antara server dan aplikasi, tetapi juga benar-benar di mana saja di tumpukan.
Misalnya, objek Response
Starlette adalah aplikasi ASGI itu sendiri. Bahkan, kita dapat mempersingkat kode dalam contoh aplikasi di atas menjadi ini:
Betapa konyolnya itu terlihat ?!
Tapi tunggu, itu belum semuanya.
Konsekuensi yang lebih dalam dari "turtles all the way" adalah bahwa kita dapat membuat semua jenis aplikasi, middleware, perpustakaan dan proyek lainnya dan memastikan bahwa mereka kompatibel selama mereka semua mengimplementasikan antarmuka aplikasi ASGI.
(Selain itu, dari pengalaman pribadi saya membangun Bocadillo , sangat sering menerima antarmuka ASGI (jika tidak selalu) mengarah ke kode yang lebih bersih)
Misalnya, kita dapat membuat middleware ASGI (mis. Aplikasi yang membungkus aplikasi lain) untuk menampilkan waktu yang dibutuhkan untuk permintaan untuk diselesaikan:
Untuk menggunakannya, kami cukup membungkus aplikasi dengan itu ...
... dan secara ajaib itu hanya akan berfungsi.
$ uvicorn app:app INFO: Started server process [59405] INFO: Waiting for application startup. INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) ... INFO: ('127.0.0.1', 62718) - "GET / HTTP/1.1" 200 Took 1.00 seconds
Sungguh TimingMiddleware
bahwa di TimingMiddleware
Anda dapat membungkus aplikasi ASGI. Aplikasi internal dalam contoh ini sangat sederhana, tetapi bisa menjadi proyek nyata yang lengkap (bayangkan ratusan API dan titik akhir WebSocket) - tidak masalah selama antarmuka kompatibel dengan ASGI.
(Ada versi middleware ini yang lebih siap untuk keperluan industri: timing-asgi .)
Kenapa harus repot?
Sementara saya pikir kompatibilitas adalah argumen yang sangat kuat, ada banyak keuntungan menggunakan komponen berbasis ASGI untuk membangun aplikasi web Python.
- Kecepatan: Sifat asinkron dari aplikasi dan server ASGI membuatnya sangat cepat (setidaknya untuk Python) - kita berbicara tentang permintaan 60k-70k per detik (dengan asumsi bahwa Flask dan Django hanya mencapai 10-20k dalam situasi yang sama).
- Fitur: Server dan platform ASGI memberi Anda akses ke fungsi-fungsi paralel yang esensial (WebSocket, Server-Sent Events, HTTP / 2) yang tidak dapat diimplementasikan menggunakan kode sinkron dan WSGI.
- Stabilitas: ASGI sebagai spesifikasi telah ada selama 3 tahun, dan versi 3.0 dianggap sangat stabil. Akibatnya, bagian utama ekosistem menjadi stabil.
Dari sudut pandang perpustakaan dan alat, saya tidak berpikir bahwa kita dapat mengatakan bahwa kita telah mencapai tingkat yang diperlukan. Tetapi berkat komunitas yang sangat aktif, saya memiliki harapan besar bahwa ekosistem ASGI akan segera mencapai kesamaan fungsi dengan ekosistem sinkron / WSGI tradisional.
Di mana saya dapat menemukan komponen yang kompatibel dengan ASGI?
Bahkan, semakin banyak orang membangun dan meningkatkan proyek berdasarkan ASGI. Jelas ini adalah server dan kerangka kerja web, tetapi ada aplikasi middleware dan berorientasi produk seperti Datasette juga.
Berikut adalah beberapa contoh komponen non-web yang menarik minat saya:
Sungguh menakjubkan untuk mengamati bahwa ekosistem berkembang dengan sukses, namun, secara pribadi sulit bagi saya secara pribadi untuk mengikuti perubahan.
Itu sebabnya saya membuat asgi yang luar biasa . Saya harap ini membantu semua orang mengikuti semua hal menakjubkan yang terjadi di dunia ASGI. (Dan melihat bahwa ia hampir mencapai 100 bintang dalam beberapa hari, saya merasa bahwa benar-benar ada kebutuhan untuk mengumpulkan informasi tentang sumber daya ASGI di satu tempat.)
Kesimpulan
Meskipun ini mungkin terlihat seperti detail implementasi, saya yakin ASGI telah meletakkan dasar untuk era baru dalam pengembangan web Python.
Jika Anda ingin mempelajari lebih lanjut tentang ASGI, periksa berbagai publikasi (artikel dan pidato) yang terdaftar di awesome-asgi
. Jika Anda ingin menyentuhnya, coba salah satu proyek berikut:
Proyek-proyek ini dibuat dan didukung oleh Encode, terutama Tom Christie. Ada diskusi terbuka tentang cara membuat tim dukungan Encode , jadi jika Anda mencari peluang untuk berpartisipasi dalam pengembangan sumber terbuka, maka Anda memiliki kesempatan seperti itu!
Bersenang-senang bepergian ke dunia ASGI!