abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
AbcLinuxu hledá autory!
Inzerujte na AbcPráce.cz od 950 Kč
Rozšířené hledání
×
    dnes 20:11 | Komunita

    V Londýně probíhá dvoudenní Ubuntu Summit 25.10. Na programu je řada zajímavých přednášek. Zhlédnout je lze také na YouTube (23. 10. a 24. 10.).

    Ladislav Hagara | Komentářů: 0
    dnes 13:22 | Nová verze

    Gemini CLI umožňuje používání AI Gemini přímo v terminálu. Vydána byla verze 0.10.0.

    Ladislav Hagara | Komentářů: 0
    dnes 12:55 | Pozvánky

    Konference OpenAlt 2025 proběhne již příští víkend 1. a 2. listopadu v Brně. Nabídne přibližně 80 přednášek a workshopů rozdělených do 7 tematických tracků. Program se může ještě mírně měnit až do samotné konference, a to s ohledem na opožděné úpravy abstraktů i případné podzimní virózy. Díky partnerům je vstup na konferenci zdarma. Registrace není nutná. Vyplnění formuláře však pomůže s lepším plánováním dalších ročníků konference.

    Ladislav Hagara | Komentářů: 0
    dnes 05:33 | IT novinky

    Samsung představil headset Galaxy XR se 4K Micro-OLED displeji, procesorem Snapdragon XR2+ Gen 2, 16 GB RAM, 256 GB úložištěm, operačním systémem Android XR a Gemini AI.

    Ladislav Hagara | Komentářů: 2
    dnes 05:22 | Nová verze

    Před konferencí Next.js Conf 2025 bylo oznámeno vydání nové verze 16 open source frameworku Next.js (Wikipedie) pro psaní webových aplikací v Reactu. Přehled novinek v příspěvku na blogu.

    Ladislav Hagara | Komentářů: 0
    včera 23:33 | Komunita

    Sovereign Tech Fund oznámil finanční podporu následujících open source projektů: Scala, SDCC, Let's Encrypt, Servo, chatmail, Drupal, Fedify, openprinting, PHP, Apache Arrow, OpenSSL, R Project, Open Web Docs, conda, systemd a phpseclib.

    Ladislav Hagara | Komentářů: 0
    včera 13:11 | Nová verze

    Bylo vydáno OpenBSD 7.8. S předběžnou podporou Raspberry Pi 5. Opět bez písničky.

    Ladislav Hagara | Komentářů: 0
    včera 05:44 | Nová verze Ladislav Hagara | Komentářů: 2
    včera 05:22 | Bezpečnostní upozornění

    Byly publikovány informace o kritické zranitelnosti v knihovně pro Rust async-tar a jejích forcích tokio-tar, krata-tokio-tar a astral-tokio-tar. Jedná se o zranitelnost CVE-2025-62518 s CVSS 8.1. Nálezci je pojmenovali TARmageddon.

    Ladislav Hagara | Komentářů: 5
    21.10. 23:15 | Nová verze

    AlmaLinux přinese s verzí 10.1 podporu btrfs. XFS bude stále jako výchozí filesystém, ale instalátor nabídne i btrfs. Více informací naleznete v oficiálním oznámení.

    Max | Komentářů: 3
    Jaké řešení používáte k vývoji / práci?
     (36%)
     (49%)
     (20%)
     (20%)
     (23%)
     (18%)
     (21%)
     (18%)
     (18%)
    Celkem 261 hlasů
     Komentářů: 14, poslední 14.10. 09:04
    Rozcestník

    Zlý vtip menom async v djangu (pythone)

    dnes 15:36 | Přečteno: 271× | Programovanie | poslední úprava: dnes 15:36

    Práce na asynchronnom Djangu začali okolo roku 2020. Je rok 2025. Čo tak sa pozrieť, čo sme za tú dobu získali?

    Päť rokov je v oblasti IT veľmi dlhá doba aby async prestal ignorovať aj taký technologický konzervatívec a spiatočník ako ja. Po všetkých tých fantastických blogoch a benchamrkoch som nasadol na vlnu asyncu.

    Nie až tak dávno som začal nový projekt v asynchrónnom frameworku FastAPI. Nebudem rozoberať, prečo som sa rozhodol práve pre Django v úlohe ORM. Akonáhle som sa začal trocha hrabať vo vnútornostiach, šokovalo ma ako zle všetko funguje. Tento blog bude o čistom djangu.

    Výkon

    Blogy sľubujú výkon. Tak moje konzervatívne skostnatené ja si spustí zastaralý uWSGI a oproti tomu postavím uvicorn. Oba s jedným workerom. Môj naivný view vyzerá ako väčšina dnešných benchmarkov. Veď prečo sa pozerať na komplexnú aplikáciu keď môžeme merať nič?

    from django.http.response import JsonResponse
    
    
    def naive_sync(request):
        return JsonResponse({"status": "ok"})
    
    
    async def naive_async(request):
        return JsonResponse({"status": "ok"})
    

    S týmto viewom si spustím benchmark pre 10 simultánnych požiadaviek a 1000 celkovo:

    ab -n 1000 -c 10 'http://127.0.0.1:8000/naive/sync/'

    Výsledný graf zobrazuje synchrónne volanie v uWSGI, potom synchrónne uvicorn a asynchrónne uvicorn. Vyššie číslo udáva vyššiu priepustnosť.

    Naivná implementácia

    Obrázok 1: Naivná implementácia

    Čo sa stalo? No jednoducho v tomto príklade nemala ako vyniknúť asynchrónnosť. Okrem toho uWSGI je napísaný v C, ale oproti python implementácii je to rozdiel len 2ms na pižiadavku. Nie je to nič, čo by mi žily trhalo v reálnej aplikácii. Tento benchmark je nanič a som si toho vedomý.

    Chceme ešte jeden nanič benchmark? Samozrejme! Tak teda to isté so 16 workermi.

    Naivná implementácia so 16 workermi

    Obrázok 2: Naivná implementácia so 16 workermi

    Trocha realistickejší príklad

    Väčšina aplikácií hrabe do databázy a tak si vytvorme pár tabuliek:

    from django.db import models
    
    
    class Author(models.Model):
        name = models.CharField(max_length=100)
    
    
    class Category(models.Model):
        name = models.CharField(max_length=100)
    
    
    class Document(models.Model):
        name = models.CharField(max_length=100)
        authors = models.ManyToManyField(Author, related_name='documents')
        category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='documents', null=True)
    

    Po naplnení databázy som ešte napísal jeden synchrónny a jeden asynchrónny view.

    from asgiref.sync import sync_to_async
    from django.http.response import JsonResponse
    from .models import Document
    
    
    def db_sync(request):
        data = []
        for document in Document.objects.order_by('pk'):
            authors = []
            data.append(
                {
                    "name": document.name,
                    "category": document.category.name,
                    "authors": authors,
                }
            )
            for author in document.authors.all():
                authors.append({"name": author.name})
        return JsonResponse({"data": data})
    
    
    async def db_async(request):
        data = []
        async for document in Document.objects.order_by('pk'):
            authors = []
            data.append(
                {
                    "name": document.name,
                    "category": (await sync_to_async(getattr)(document, 'category')).name,
                    "authors": authors,
                }
            )
            async for author in document.authors.all():
                authors.append({"name": author.name})
        return JsonResponse({"data": data})
    

    Vytvoril som dve prakticky rovnaké funkcie líšiace sa len v dvoch detailoch. Prvým je volanie generátora for. V jednom prípade je synchrónny (for) a v druhom prípade asynchrónny (async for). No a potom je tu táto šialenosť:

    (await sync_to_async(getattr)(document, 'category')).name

    Python neumožňuje kombinovať synchrónne a asynchrónne funkcie. Napíšete jedinú funkciu asynchrónne a musíte prepísať všetky funkcie, ktoré ju volajú. V postate tým infikujete celý kód. Ak ste tvorcom knižnice, môžete buď napísať knižnicu syncrhónne, alebo asynchrónne, alebo oboma spôsobmi pričom každú funkciu napíšete 2x a bude sa v 99% prípadov líšiť v tomto:

    # async
    async def afunkcia():
       ...
       await ainafunkcia()
       ...
    
    # sync
    def funkcia():
       ...
       inafunkcia()
       ...
    

    Django začala ako synchrónna knižnica a postupne sa duplikuje kód. Niektoré „drobnosti“ nie sú doteraz podporované ako napríklad transakcie. No a potom sú tu ešte veci, ktoré sa nedajú prepísať ako napríklad property, kde .category potrebuje zavolať SQL dotaz, ale propery nie je polymorfná a tak volá len syncrhónny select, ktorý sa nedá zavolať z asynchrónneho kontextu. Zabalíme to teda do sync_to_async

    Prístup do databázy

    Obrázok 3: Prístup do databázy

    To nie je možné!?! Dajme tam 16 workerov. Nech sa ukáže asyncrhṕnnosť.

    Prístup do databázy so 16 workermi

    Obrázok 4: Prístup do databázy so 16 workermi

    Ešte väčšia katastrofa, čo? Rozmeňme si to na drobné. Databázový driver, ktorý django používa je synchrónny. Aj keby nebol, tak celá implementácia Djanga je hračkárska a vyzerá takto:

    async def aget(self, *args, **kwargs):
        return await sync_to_async(self.get)(*args, **kwargs)
    

    V tomto momente dochádza k prepnutiu kontextu, čo môže trvať rádovo okolo 1ms. Nie je dostatok vývojárov, aby implementovali a udržiavali Django so skoro každou duplikovanou funkciou. Preto sa len hráme na akože asynchrónnosť. Mimochodom viete, že veľa vývojárov vo svojich knižniciach overriduje save, aby tam pridali napríklad nejakú logiku, ja neviem date_created = now? Teraz to funguje pretože asave vyzerá takto: sync_to_async(self.save). Teraz si predstavte ako sa django knižnice začnú rozpadávať až sa začne reálne implementovať async. Celý ekosystém, desaťtisíce knižníc sa musia prepísať.

    Nakoniec ešte doplním úpravu vďaka ktorej sa spustia len 2 dotazy namiesto 300:

    def db_opt_sync(request):
        data = []
        for document in Document.objects.order_by('pk').prefetch_related('authors').select_related('category'):
            authors = []
            data.append(
                {
                    "name": document.name,
                    "category": document.category.name,
                    "authors": authors,
                }
            )
            for author in document.authors.all():
                authors.append({"name": author.name})
        return JsonResponse({"data": data})
    
    
    async def db_opt_async(request):
        data = []
        async for document in Document.objects.order_by('pk').prefetch_related('authors').select_related('category'):
            authors = []
            data.append(
                {
                    "name": document.name,
                    "category": (await sync_to_async(getattr)(document, 'category')).name,
                    "authors": authors,
                }
            )
            async for author in document.authors.all():
                authors.append({"name": author.name})
        return JsonResponse({"data": data})
    
    Prístup do databázy so 16 workermi po optimalizácii

    Obrázok 5: Prístup do databázy so 16 workermi po optimalizácii

    Záver

    Čo som vlastne chcel povedať? Neverte všetkým sladkým rečiam v blogoch. Python má svoju filozofiu „explicit is better“ a nej podriadil aj implementáciu async. Autori knižníc sa teraz musia rozhodnúť, či budú písať synchrónne, asynchrónne, alebo budú svoj kód duplikovať, budú mať 2x viac práce a 2x viac chýb. Pritom v dynamickom jazyku s tak neskorou adaptáciou async / await nebolo farbenie vôbec nevyhnutné. Škoda. Z môjho pohľadu premárnená príležitosť urobiť lepší jazyk.

           

    Hodnocení: 50 %

            špatnédobré        

    Obrázky

    Zlý vtip menom async v djangu (pythone), obrázek 1 Zlý vtip menom async v djangu (pythone), obrázek 2 Zlý vtip menom async v djangu (pythone), obrázek 3 Zlý vtip menom async v djangu (pythone), obrázek 4 Zlý vtip menom async v djangu (pythone), obrázek 5

    Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

    Komentáře

    Vložit další komentář

    mirec avatar dnes 15:39 mirec | skóre: 32 | blog: mirecove_dristy | Poprad
    Rozbalit Rozbalit vše Re: Zlý vtip menom async v djangu (pythone)
    Příloha:

    Keďže sa k blogu nedá priložiť súbor prikladám tu. Veľa sa tu na abclinuxu od mojej poslednej návštevy nezmenilo. Akurát ja som o dosť starší, šedivejší a bývam s 10 mačkami v dome.

    LinuxOS.sk | USE="-fotak -zbytocnosti -farebne_lcd +vydrz +odolnost +java" emerge telefon
    dnes 18:02 Want
    Rozbalit Rozbalit vše Re: Zlý vtip menom async v djangu (pythone)

    Veľa sa tu na abclinuxu od mojej poslednej návštevy nezmenilo. Akurát ja som o dosť starší, šedivejší a bývam s 10 mačkami v dome.

    To je teda ale smutný příběh.

    mirec avatar dnes 18:17 mirec | skóre: 32 | blog: mirecove_dristy | Poprad
    Rozbalit Rozbalit vše Re: Zlý vtip menom async v djangu (pythone)

    Smutný ani nie, ale 10 mačiek je dobrý začiatok konverzácie :P Sám nie som, mám partnerku, ktorá má rada mačky, veľa cestujem, mám catsittera kým som preč, veľa koníčkov, aktivít. Škoda akurát, že dni nemajú viac hodín.

    LinuxOS.sk | USE="-fotak -zbytocnosti -farebne_lcd +vydrz +odolnost +java" emerge telefon
    dnes 20:26 _
    Rozbalit Rozbalit vše Re: Zlý vtip menom async v djangu (pythone)
    nemackej macky nemaj to rady
    vlk avatar dnes 20:15 vlk | skóre: 23 | blog: u_vlka
    Rozbalit Rozbalit vše Re: Zlý vtip menom async v djangu (pythone)
    Ja som vobec neprisiel na chut async-u. Davam prednost prehladnosti, jednoduchosti a dobremu navrhu pred nejakymi sialenstvami. Ak potrebujem nieco naozaj paralelne (ale akoze naozaj - ze inak sa neda) tak mam stale v zalohe multiprocessing.Process a vynimocne este Thread. A obcas mi padne do vyuzitia yield a tam to konci. Ale mozno ta nechut do async asi bude aj tym sedivenim (a to nemam ziadne macky!)
    You don't exist, Go away !
    dnes 20:21 RealJ | skóre: 8
    Rozbalit Rozbalit vše Re: Zlý vtip menom async v djangu (pythone)
    Zajimave, ja to mam presne naopak.
    dnes 20:20 RealJ | skóre: 8
    Rozbalit Rozbalit vše Re: Zlý vtip menom async v djangu (pythone)
    Ja ti nevim, kdyz neco pisu (jako amater), tak to vzdy pisu pro async. Psat v dobe 100+ core CPU a ruznych clustru neco synchronne mi prijde jako nevyuziti dostupneho vykonu. Delam hodne s daty v ruznych formatech (jako amater) a nezpracovavat je asynchronne by me zabilo. K tomu blogpostu - nevim co mas za db ale mozna narazis na db limits.
    dnes 20:23 mimi.vx | skóre: 37 | blog: Mimi.VX | Praha
    Rozbalit Rozbalit vše Re: Zlý vtip menom async v djangu (pythone)

    az na to ze async nema s vyuzitim cpu cores moc spolecneho ...

     

    na tyto strandy jsou multiprocess a multithread moduly + concurrent.

    USE="-gnome -kde";turris
    dnes 20:33 RealJ | skóre: 8
    Rozbalit Rozbalit vše Re: Zlý vtip menom async v djangu (pythone)
    Takze async neresi “overlaping overlaping waits on single thread”? A jak chces bez async vytizit 100gbit sitovku nebo rychly storage? Ja chapu, ze async resi IO ale to je jaksi provazane s multicpu systemy.
    vlk avatar dnes 20:52 vlk | skóre: 23 | blog: u_vlka
    Rozbalit Rozbalit vše Re: Zlý vtip menom async v djangu (pythone)
    spracovanie dat zo 100gbit siete nebudem riesit v pythone
    You don't exist, Go away !
    mirec avatar dnes 20:37 mirec | skóre: 32 | blog: mirecove_dristy | Poprad
    Rozbalit Rozbalit vše Re: Zlý vtip menom async v djangu (pythone)

    Async kód využíva kooperatívny multitasking. Niečo, čo vzniklo v dobách jednoprocesorových strojov. Spoliehať sa len na async znamená využívať jediné jadro. Ak sa bavíme o pythone tak správnou cestou je multiprocessing, alebo subinterpretery alebo novy no-GIL. Inak sa bude striedavo využívať jediné jadro.

    Správnym využitím async je v prípadoch, keď sa čaká na IO, ale aj vtedy môže byť rozumnejšie kombinovať multiprocessing s asyncom a nemať jeden veľký loop pri veľkom množstve spojení s väčšou priepustnosťou.

    Sám by som rád písal čistý async kód, ale knižnice, ktoré používam nie sú prepísané do async a nik ich do async celkom neche prepísať, lebo by bolo potrebné prepísať komplet kód, ktorý ich využíva a vlastne musel by sa infikovať celý ekosystém.

    Na limity databázy nenarážam. Používam PostgreSQL 17 s nastavenými max 100 connections.

    LinuxOS.sk | USE="-fotak -zbytocnosti -farebne_lcd +vydrz +odolnost +java" emerge telefon
    vlk avatar dnes 20:49 vlk | skóre: 23 | blog: u_vlka
    Rozbalit Rozbalit vše Re: Zlý vtip menom async v djangu (pythone)
    zabudni na 100+ core, async bezi na jedinom vlakne, navyse to ma aj nejaky overhead ked prepina medzi ulohami ktore spracovava asynchronne. s obycajnym selectom dosiahnes lepsie vysledky..
    You don't exist, Go away !

    Založit nové vláknoNahoru

    ISSN 1214-1267   www.czech-server.cz
    © 1999-2015 Nitemedia s. r. o. Všechna práva vyhrazena.