Programowanie asynchroniczne stało się kluczowym elementem języka Python. Dla twórców aplikacji internetowych otwierają się nowe horyzonty dzięki szerokiej gamie zaawansowanych frameworków.
Obecnie asynchroniczność nie jest już tylko popularnym trendem w społeczności Pythona. Wraz z wprowadzeniem biblioteki asyncio w wersji 3.5, Python docenił wpływ Node.js na tworzenie stron internetowych i włączył do swojego języka dwa nowe słowa kluczowe: async i await. Było to znaczące wydarzenie, ponieważ Python bardzo ostrożnie podchodzi do rozszerzania swojej podstawowej składni, tylko gdy istnieje ku temu pilna potrzeba. To podkreśla, jak fundamentalne dla programistów Pythona stały się możliwości asynchroniczne.
W rezultacie otworzyły się drzwi do programowania asynchronicznego: zarówno nowe, jak i istniejące biblioteki zaczęły wykorzystywać funkcje współprogramów, frameworki asynchroniczne zyskały popularność, a nowe wciąż powstają. Osiągnięcie wydajności porównywalnej lub lepszej niż Node.js nie jest niczym niezwykłym, a jeśli Twoje wzorce obciążenia nie wiążą się z dużą ilością zadań intensywnie korzystających z procesora, możesz obsłużyć nawet kilka tysięcy żądań na sekundę.
Ale dość o motywacji!
Przyjrzyjmy się aktualnej sytuacji w Pythonie i zbadajmy kilka najlepszych frameworków asynchronicznych.
Tornado
Zaskakujące może być to, że Tornado nie jest wcale nowym frameworkiem. Jego debiut miał miejsce w 2009 roku i od tego czasu koncentruje się na zapewnieniu solidnego, asynchronicznego programowania z wysoką współbieżnością.
Tornado nie jest zasadniczo frameworkiem internetowym. To raczej zbiór asynchronicznych modułów, które są również wykorzystywane do budowy webowego frameworka. Dokładniej, te moduły obejmują:
- Współprogramy i inne elementy (tornado.gen, tornado.locks, tornado.queues itp.)
- Moduły sieciowe (tornado.ioloop, tornado.iostream itp.)
- Serwery i klienci asynchroniczni (tornado.httpserver, tornado.httpclient itp.)
Zostały one połączone w celu utworzenia modułów finalnego frameworka: tornado.web, tornado.routing, tornado.template itd.
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
Tornado ma silną i oddaną społeczność w świecie Pythona i jest wykorzystywany przez doświadczonych architektów do budowy bardzo wydajnych systemów. Jest to framework, który od dawna oferuje rozwiązania problemów ze współbieżnością, ale być może nie stał się głównym wyborem, ponieważ nie obsługuje standardu WSGI i był nieco zbyt rozbudowany. (Należy pamiętać, że większość bibliotek Pythona nadal działa synchronicznie).
Sanic
Sanic jest „nowoczesnym” frameworkiem w pełnym tego słowa znaczeniu: nie wspiera wersji Pythona starszych niż 3.6, a od razu po wyjęciu z pudełka obsługuje prostą i jednolitą składnię async/await. Dzięki temu nie trzeba przedzierać się przez ogrom dokumentacji ani pamiętać o nietypowych sytuacjach, zanim napisze się swój pierwszy program obsługujący protokół HTTP.
W rezultacie uzyskana składnia jest całkiem przyjemna (przynajmniej moim zdaniem); przypomina kod, który można by napisać z dowolnym innym mikroframeworkiem (na przykład Flask, CherryPy), ale z kilkoma dodatkami asynchronicznymi:
from sanic import Sanic
from sanic.response import json
app = Sanic()
@app.route("/")
async def test(request):
return json({"hello": "world"})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
Sanic jest prawdopodobnie najbardziej popularnym i lubianym frameworkiem asynchronicznym w środowisku Pythona. Oferuje niemal wszystkie funkcje potrzebne w projektach: routing, oprogramowanie pośredniczące, pliki cookie, wersjonowanie, plany, widoki oparte na klasach, pliki statyczne, przesyłanie strumieniowe, gniazda itp. A to, czego nie ma w standardzie – szablony, obsługa baz danych, operacje wejścia/wyjścia plików, kolejki – można dodać, ponieważ obecnie dostępnych jest wystarczająco dużo bibliotek asynchronicznych.
Vibora
Vibora jest bliskim krewnym Sanica, z tą różnicą, że skupia się na byciu najszybszym serwerem WWW w Pythonie. Już na stronie głównej wita nas porównanie z innymi frameworkami:
Jak widać, Vibora twierdzi, że jest kilkukrotnie szybsza od klasycznych frameworków i ponad dwukrotnie szybsza od swojego najbliższego rywala, czyli Sanica. Oczywiście, do wyników benchmarków należy podchodzić z pewną dozą sceptycyzmu.
Chociaż pod względem składni i funkcji Vibora jest porównywalna z Sanic (a może nawet trochę lepsza, ponieważ zawiera popularne biblioteki, a takie elementy jak szablony są dostępne od razu po instalacji), uważam, że Sanic jest bardziej dojrzały, ponieważ istnieje dłużej i ma większą społeczność.
from vibora import Vibora, JsonResponse
app = Vibora()
@app.route('/')
async def home():
return JsonResponse({'hello': 'world'})
if __name__ == '__main__':
app.run(host="0.0.0.0", port=8000)
Jeśli jednak priorytetem jest dla Ciebie wydajność, Vibora może być dobrym wyborem. Trzeba jednak pamiętać, że w chwili pisania tego tekstu Vibora przechodzi całkowite przepisanie, aby stać się jeszcze szybsza. Odnośnik do wersji wydajnościowej sugeruje, że prace nad nią są w toku. Może to być rozczarowujące dla tych, którzy wcześniej wybrali Viborę, ponieważ wkrótce będą musieli zmierzyć się z istotnymi zmianami, ale należy pamiętać, że asynchroniczny świat Pythona jest wciąż na początku swojej drogi i nikt nie oczekuje, że wszystko będzie od razu stabilne.
Quart
Jeśli lubisz programować we Flasku, ale brakuje Ci obsługi asynchronicznej, Quart prawdopodobnie przypadnie Ci do gustu.
Quart jest zgodny ze standardem ASGI, który jest następcą znanego standardu WSGI i oferuje obsługę asynchroniczną. Interesujące jest to, że Quart jest nie tylko podobny do Flaska, ale jest z nim zgodny pod względem API! Twórca tego frameworka chciał zachować charakter Flaska i po prostu dodać do niego obsługę async, WebSockets i HTTP 2. W rezultacie możesz nauczyć się Quarta bezpośrednio z dokumentacji Flaska, pamiętając tylko, że funkcje Quarta są asynchroniczne.
from quart import Quart
app = Quart(__name__)
@app.route('/')
async def hello():
return 'hello'
app.run()
Czujesz się (prawie) jak we Flasku, prawda?!
Ponieważ Quart jest ewolucją Flaska, dostępne są w nim wszystkie funkcje Flaska: routing, oprogramowanie pośredniczące, sesje, szablony, plany i tak dalej. Możesz nawet używać rozszerzeń Flaska bezpośrednio w Quarcie. Jedynym warunkiem jest obsługa wyłącznie Pythona 3.7+, ale jeśli nie korzystasz z najnowszej wersji Pythona, to może asynchroniczność nie jest właściwą drogą dla Ciebie.
Dokumentacja jest bardzo potrzebna, zwłaszcza jeśli nie masz doświadczenia z Flaskiem. Mimo to, mogę polecić Quarta, ponieważ jest to prawdopodobnie jedyny framework asynchroniczny, który wkrótce doczeka się wersji 1.0.
FastAPI
Ostatnim (ale nie mniej ważnym) frameworkiem na tej liście jest FastAPI. Nie, to nie jest framework przeznaczony tylko do API. W rzeczywistości FastAPI wydaje się być najbardziej funkcjonalnym i najlepiej udokumentowanym frameworkiem, jaki spotkałem podczas badania asynchronicznych frameworków Pythona.
Warto zaznaczyć, że autor tego frameworka dogłębnie przeanalizował wiele innych frameworków, od tych starszych, takich jak Django, po te nowoczesne, jak Sanic. Przyjrzał się również innym technologiom, jak NestJS (framework sieciowy dla Node.js, używający Typescript). Ich filozofię rozwoju i szczegółowe porównania można znaleźć tutaj.
Składnia jest bardzo przyjemna. Można nawet powiedzieć, że jest o wiele lepsza od innych frameworków, które do tej pory widzieliśmy:
from fastapi import FastAPI
app = FastAPI()
@app.get("/users/me")
async def read_user_me():
return {"user_id": "the current user"}
@app.get("/users/{user_id}")
async def read_user(user_id: str):
return {"user_id": user_id}
A teraz lista najważniejszych funkcji, które sprawiają, że FastAPI wyróżnia się na tle innych frameworków:
Automatyczne generowanie dokumentacji API: Jak tylko zdefiniujesz swoje punkty końcowe, możesz zacząć testować API za pomocą standardowego interfejsu użytkownika. Obsługiwane są SwaggerUI, ReDoc i inne.
Framework generuje również automatyczną dokumentację modelu danych za pomocą schematu JSON.
Nowoczesne podejście: Tak, słowo „nowoczesny” jest często nadużywane, ale uważam, że w przypadku FastAPI jest to uzasadnione. Wstrzykiwanie zależności i podpowiedzi typów są w nim bardzo istotne, co nie tylko wymusza dobre praktyki kodowania, ale także zapobiega błędom i nieporozumieniom w dłuższej perspektywie.
Szczegółowa dokumentacja: Nie wiem jak wy, ale ja jestem wielkim fanem dobrej dokumentacji. W tej kwestii FastAPI nie ma sobie równych. Strony dokumentacji wyjaśniają każdy, nawet najdrobniejszy szczegół, a także ostrzegają programistów na wszystkich poziomach zaawansowania. Czuję, że w dokumentację włożono dużo serca i wysiłku. Jedyne porównanie, jakie przychodzi mi na myśl, to dokumentacja Django (tak, dokumentacja FastAPI jest aż tak dobra!).
Poza podstawami: FastAPI obsługuje WebSockets, przesyłanie strumieniowe, a także GraphQL, a oprócz tego oferuje wszystkie tradycyjne elementy pomocnicze, takie jak CORS, sesje, pliki cookie itp.
A co z wydajnością? FastAPI jest zbudowany na bibliotece Starlette, która zapewnia wydajność porównywalną z Node.js, a w niektórych przypadkach nawet z Go! Podsumowując, naprawdę uważam, że FastAPI ma szansę stać się najlepszym asynchronicznym frameworkiem dla Pythona.
Wnioski
Obecnie wiele dzieje się w asynchronicznym środowisku Pythona. Pojawiają się nowe frameworki, stare są przepisywane, a biblioteki ewoluują, aby pasować do koncepcji asynchroniczności. Chociaż Python ma wbudowaną obsługę pętli zdarzeń i można tworzyć asynchroniczne fragmenty aplikacji, możesz też zdecydować się na kompleksowe rozwiązanie i budować na jednej z platform tutaj wymienionych. Pamiętaj jednak, że musisz mieć na uwadze długoterminową perspektywę. Niektóre asynchroniczne frameworki Pythona są w fazie intensywnego rozwoju, co może negatywnie wpłynąć na proces tworzenia i podnieść koszty dla biznesu. Ostrożność jest kluczowa!
Podsumowując, Python jest gotowy do użycia w produkcji, jeśli chodzi o wydajne frameworki internetowe. Jeśli od dawna myślałeś o migracji do Node.js, teraz nie musisz!
Brzmi dobrze? Rozpocznij swoją przygodę z Pythonem już dziś!