Upgrade to Pro — share decks privately, control downloads, hide ads and more …

async def django(): (French version)

async def django(): (French version)

DEP0009 : La proposition d’Andrew Godwin d’ajouter le support asynchrone à Django a été acceptée en Juillet. En quoi consiste-t-elle ? Que va-t-elle changer ? Et comment participer à la transition ?

E122b75d171a1029ba808f7e26af1820?s=128

Joachim Jablon

September 13, 2019
Tweet

More Decks by Joachim Jablon

Other Decks in Programming

Transcript

  1. Une petite page de pub

  2. async def django(): Joachim Jablon - DjangoCong 2019 Marseille

  3. Qui suis-je ? ! Joachim Jablon Dev @ PeopleDoc @ewjoachim

    / https://ewjoach.im
  4. Qui a déjà..? "#$%& Entendu parler d'Andew Godwin ? Lu

    du code Python asynchrone ? Ecrit du code Python Asynchrone ? Lu la DEP 0009 ?
  5. Andrew Godwin South Django Channels Core dev Django ...DEP 0009

  6. Partie 1 Le pourquoi

  7. Que fait votre serveur web ? Des I/Os (réseau /

    disque) Des cycles CPU (calculs) Python délègue
 à l'OS (appel système) Python parle au CPU directement Python sait
 le paralléliser dans des threads Python ne sait pas le paralléliser ( GIL ) >90%* <10%* *au doigt mouillé
  8. Les threads & Python Serveur qui envoie du pâté (végan

    ) 100+ requêtes simultanées 100 threads ☠ Context Switching & GIL
  9. Et si les threads coopéraient ? La partie CPU s'exécute

    sans interruption Quand elle lance un IO, elle s'interrompt,
 et laisse la place a une autre partie CPU L'IO s'exécute en tâche de fond,
 quand il est fini, il indique
 que le CPU peut reprendre Boucle d'évènements CPU I/O A A A A A B B B C C C
  10. async / await (3.5/6+) async def coroutine(length: int): await another_coroutine(length)

    return 2 * length
  11. async / await async def coroutine(length: int): await asyncio.sleep(length) return

    2 * length
  12. async / await async def view(request: Request) -> Response: user

    = await orm.get_user(id=request.id) return JsonResponse({"hello": user.full_name})
  13. Appels def func(): a = sync_network() def func(): a =

    asyncio.run( async_network() ) async def coro(): a = await loop.run_in_executor( ThreadPoolExecutor(), sync_network ) async def coro(): a = await async_network() Appeler du code: Synchrone Asynchrone Depuis
 du code: Synchrone Asynchrone
  14. Contre-exemples ❌ async def coro(): sync_network() async def coro(): k

    = 1 for i in range(1, 1e32): k *= i ** i def func(): await async_network() def func(): async_network()
  15. A A A A A A B B B C

    C C A a oublié d'appeler ses I/O en asynchrones A A A B C C A C L'exemple de tout a l'heure CPU I/O A A A A A B B B C C C B lance une tâche gourmande en CPU
  16. Disclaimer C'est vachement compliqué, ce truc quand même

  17. Partie II Le quoi

  18. WSGI Une application est un callable Reçoit une requête HTTP,

    renvoie la réponse HTTP Plutôt adapté pour HTTP (mais un peu vieillot)
  19. Les WebSockets Canal bidirectionnel Plusieurs échanges ♾ Imcompatible avec WSGI

  20. ASGI Recevoir et envoyer plusieurs fois par requête Asynchrone

  21. ASGI async def app(scope, receive, send): assert scope['type'] == 'http'

    # or 'websocket' ...
  22. ASGI ... await send({ 'type': 'http.response.start', 'status': 200, 'headers': [

    [b'content-type', b'text/plain'], ] ...
  23. ASGI ... await send({ 'type': 'http.response.body', 'body': b'Hello, world!', })

  24. Rendre Django
 compatible ASGI et async Et résoudre la faim

    et la paix dans le monde tant qu'à y être...
  25. Les défis Async complètement optionnel Ne pas casser la rétro-compatibilité

    API familière "Thread sensitivity"
  26. Partie III Le comment

  27. La structure de Django WSGI Server View Middleware Handler URL

    router Form Template ORM From "Just Add Await: Retrofitting Async Into Django" - Andrew Godwin (PyCon AU 2019)
  28. Phase 3 ORM async Phase 2: vues async Phase 1

    Serveur async Le plan ASGI/WSGI Server View Middleware Handler URL router Form Template ORM From "Just Add Await: Retrofitting Async Into Django" - Andrew Godwin (PyCon AU 2019) Phase 4+
 le reste
  29. Phase 1: ASGI Bien aidé par le le couplage faible

    entre WSGI et Django:
 WSGIHandler / BaseHandler
 
 ASGIHandler Point de passage async vers sync
  30. Phase 1: ASGI WSGIHandler BaseHandler

  31. Phase 1: ASGI BaseHandler WSGIHandler ASGIHandler ⚠

  32. (r)Appels a = sync_func() a = asyncio.run( async_func() ) a

    = await loop.run_in_executor( ThreadPoolExecutor(), sync_func ) a = await async_func() Appeler du code: Synchrone Asynchrone Depuis
 du code: Synchrone Asynchrone
  33. sync_to_async() asgiref.sync.sync_to_async Exceptions & tracebacks, thread sensitivity, thread locals

  34. Résultat Ca marche C'est plus rapide si vous avez des

    uploads lents C'est déjà mergé dans Django 3
  35. async_to_sync() asgiref.sync.async_to_sync Compatible

  36. Phase 3 ORM async Phase 2: vues async Phase 1

    Serveur async Le plan ASGI/WSGI Server View Middleware Handler URL router Form Template ORM From "Just Add Await: Retrofitting Async Into Django" - Andrew Godwin (PyCon AU 2019) Phase 4+
 le reste
  37. Phase 2: Vues asynchrones Handler asynchrone capable de lancer: 


    - des vues synchrones (sync_to_async)
 - ou asynchrones Travail en cours, peut-etre en Django 3.1 async def my_view(request):
  38. Le problème des Middlewares Cas 1 Middleware1> Middleware2> Middleware3> Middleware4>


    Cas 2 Middleware1> Middleware2> Middleware3> Middleware4>
 Cas 3 Middleware1> Middleware2> Middleware3> Middleware4>
  39. Le problème des Middlewares Cas 1 Middleware1> Middleware2> Middleware3> Middleware4>


    Cas 2 Middleware1> Middleware2> a2s>Middleware3>s2a> Middleware4>
 Cas 3 Middleware1> a2s>Middleware2>s2a> a2s>Middleware3>s2a> Middleware4>
  40. Le problème des Middlewares Cas 1 Middleware1> Middleware2> Middleware3> Middleware4>


    Cas 2 Middleware1> Middleware2> a2s>Middleware3>s2a> Middleware4>
 Cas 3 Middleware1> a2s>Middleware2>s2a> a2s>Middleware3>s2a> Middleware4>
  41. Le problème des Templates Un template peut appeler de l'IO

    (lecture du disque) Une exception peut provoquer un template (500, 404...)
  42. Évitons de se tirer
 une balle dans le pied Décorateur

    @async_unsafe
  43. Phase 3 ORM async Phase 2: vues async Phase 1

    Serveur async Le plan ASGI/WSGI Server View Middleware Handler URL router Form Template ORM From "Just Add Await: Retrofitting Async Into Django" - Andrew Godwin (PyCon AU 2019) Phase 4+
 le reste
  44. Phase 3: L'ORM for result in Model.objects.all(): async for result

    in Model.objects.all(): instance.foreign_key
  45. Phase 4: La stratégie 1. coeur sync, utiliser sync_to_async partout

    2. coeur async, async_to_sync partout 3. Ne pas tout casser
  46. Phase 3 ORM async Phase 2: vues async Phase 1

    Serveur async Le plan ASGI/WSGI Server View Middleware Handler URL router Form Template ORM From "Just Add Await: Retrofitting Async Into Django" - Andrew Godwin (PyCon AU 2019) Phase 4+
 le reste
  47. Merci Des questions ?