» »

Python primer async/await

Python primer async/await

marjan_h ::

Za primer razumevanja sem napisal majhen program v Pythonu z uporabo asyncio:

async def prastevilo(a):
    stevila = []
    print("Stevilo: " + str(a))
    for i in range(1,a+1):
        if a % i == 0:
            stevila.append(i)
    
    #Ta vrstica naj bi predala kontrolo naslednji funkciji ki caka v event loopu.
    await asyncio.sleep(0.01)
    
    print(len(stevila) == 2)

import time
import asyncio

async def main():
    t1 = time.time()
    await prastevilo(133783472)
    await prastevilo(125345346)
    await prastevilo(154654642)
    t2 = time.time()
    print("Cas je: " + str(t2-t1))

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()


Mogoče, še vsega ne vem. In sicer zanima me zakaj v korutini "prastevilo", ko awaitam asyncio.sleep() ne preda kontrolo naslednji korutini, ki čaka v event loopu? Zato, ker če zakomentiram to vrstico, večje spremembe v času procesiranja main() funkcije ni. Mogoče sem še kaj pozabil?

Spura ::

Kaj je logika, po kateri bi ta sleep skrajsal cas izvajanja celega programa. Izracun teh treh prastevil traja enako, ne glede na to ali povsem zaporedno racunas ali ne.

Poleg tega tukaj skoraj povsem zaporedno racunas, sleep je po tem ko si opravil skoraj 100% dela v funkciji, torej je vseeno ce ga ne bi bilo.

marjan_h ::

Logika po kateri sem razmišljal je (ne vem če je res), da so v ozadju threadi/procesi. Kar pomeni, da ko začne računati prvo funkcijo praštevilo se paralelno začne izvajati drugo funkcijo praštevilo ipd. Verjetno se tukaj uporablja multithreading ali multiprocessing in Python izkorišča hardware, ki je na voljo npr. večjedrni procesor.

Mogoče lahko, da kdo kakšen primer izračun in uporaba aysincio? Največ je primerov na spletu z requesti. Torej če bi dal await funkcijo ki pošlje zahtevek oddaljenemu strežniku in čaka na odgovor bi delovalo.

Mavrik ::

Tvoja logika je ok z izjemo ene malenkosti - "await" je klic, ki počaka na rezultat poklicane async metode. Tako tvoja koda sploh ne teče paralelno, ker ti ukažeš Pythonu da naj počaka na rezultat klica prastevilo() - in to preden mu ukažeš izvajanje naslednje metode.

Če hočeš paralelno izvajanje po tvojem načinu, potem moraš narediti nekaj takega:
    prastevilo1 = prastevilo(133783472)
    prastevilo2 = prastevilo(125345346)
    prastevilo3 = prastevilo(154654642)

    await prastevilo1
    await prastevilo2
    await prastevilo3

ali krajše
    asyncio.wait(prastevilo1, prastevilo2, prastevilo3)

Tak vrstni red poskrbi da poženeš vse operacije preden blokiraš s čakanjem na rezultate.
The truth is rarely pure and never simple.

Zgodovina sprememb…

  • spremenil: Mavrik ()

snuderl ::

Tudi mavrikov odgovor nebo spremenil veliko. Sleep je praktično na koncu metode, tako da se bo kontrola predala šele ko boš že izračunal praštevilo... Če bi recimo želel "simulariti" asinhron potek, bi sleep dal v zanko, in potem dodal še en print. Potem bi lahko videl da se ti izvajanje prepleta.

V nobenem primeru pa se zgornja koda nebo izvajala hitreje saj asinhrono izvajanje kode != paralelno.

BigWhale ::

V bistvu mors uporabit asyncio.gather(), da hkrati pozenes vse awaitable.

V tvojem primeru bo to blo:

await asyncio.gather(
    prastevilo(133783472),
    prastevilo(125345346),
    prastevilo(154654642),
    )


Pa v Python 3.8 imas tudi asyncio.run() in lahko main pozenes kar z: asyncio.run(main()).

ragezor ::

Mavrik je izjavil:



prastevilo1 = prastevilo(133783472)
prastevilo2 = prastevilo(125345346)
prastevilo3 = prastevilo(154654642)

await prastevilo1
await prastevilo2
await prastevilo3



ne vem, ce se avtomatsko ustvari task in doda v event loop, ko poklices prastevilo(...). mislim, da moras uporabit asyncio.create_task(prastevilo(...)) in to dejansko schedula task. nisem pa ziher.

jype ::

Hkrati je vse skupaj srednja žalost, ker se CPU bound reči v pythonu strahotno slabo skalirajo. Bolje je uporabiti ProcessPoolExecutor iz concurrent futures:

https://docs.python.org/3/library/concu...

marjan_h ::

snuderl je izjavil:

Tudi mavrikov odgovor nebo spremenil veliko. Sleep je praktično na koncu metode, tako da se bo kontrola predala šele ko boš že izračunal praštevilo... Če bi recimo želel "simulariti" asinhron potek, bi sleep dal v zanko, in potem dodal še en print. Potem bi lahko videl da se ti izvajanje prepleta.

V nobenem primeru pa se zgornja koda nebo izvajala hitreje saj asinhrono izvajanje kode != paralelno.


Zelo koristen odgovor. Ja to ni asinhrona koda, hotel sem se spomniti koristen problem, ampak mi to ni uspelo. Ker razni tutoriali na spletu uporabljajo request za primer, procesor čaka, da dobi response od nekega strežnika. Ima kdo še kakšno idejo za asinhrone probleme?

Hvala @BigWhale za await asyncio.gather(), to res požene vse awaitable, vendar ni nič hitreje kot je rekel @snuderl.

jype ::

Pravim ti, da uporabi multiprocessing, ki se odlično obnese pri več jedrih.

galu ::

Za IO (npr. server response wait) je OK.

Tu je kar lepa, čeprav precej abstraktna, primerjava: https://code.luasoftware.com/tutorials/...
Tako to gre.

BigWhale ::

marjan_h je izjavil:

Hvala @BigWhale za await asyncio.gather(), to res požene vse awaitable, vendar ni nič hitreje kot je rekel @snuderl.


A si to stestiral? Ker gather() pozene stvari concurrently, zdaj, ce to spet ni nek pyhton thing, potem bi reci morale teci hitreje.

marjan_h ::

BigWhale je izjavil:

marjan_h je izjavil:

Hvala @BigWhale za await asyncio.gather(), to res požene vse awaitable, vendar ni nič hitreje kot je rekel @snuderl.


A si to stestiral? Ker gather() pozene stvari concurrently, zdaj, ce to spet ni nek pyhton thing, potem bi reci morale teci hitreje.


Ja, sem stestiral. Z gather() dobim 20 sekund, brez pa 16 sekund, kjer ni asinhron potek torej izvaja ukaze enega za drugim. Verjetno je tako kot je opisal @snuderl.

BigWhale ::

V vsakem primeru, poglej tist kar ti je Jure napisal. :)

marjan_h ::

Ne vem kdo je Jure, vendar sem pogledal link katerega je prilepil @galu, tam piše za asyncio:

Utilize single core only: concurrent but not parallel execution


Sem pa mislil, da bo kdo dal real-life primere za asyncio knjižnico npr. če je kdo kaj programiral v službi in je rabil.

BigWhale ::

jype je jure :)))

marjan_h ::

Dobro, potem pa Jure, galu in kdorkoli, če lahko napišite realno uporabo asyncio knjižnice, ki se uporablja za concurrency in ne za paralelno kodo. Ni potrebno prilepiti kode, samo primere uporabe. Ker sem kar dost o tem prebral na spletu, ampak so vedno primeri za web requeste.

Hvala.

infiniteLoop ::

Stvar je ponavadi uporabna tam kjer je precej concurrent (kako se temu rece po slovensko?) operacij, katere vecino casa porabijo za cakanje na IO. In posledicno je web streznik, ki streze mnogo zahtevkov naenkrat kar logicen primer. Ni pa to edini primer uporabe. Recimo lahko tudi concurrently izvajas vec klicov podatkovne baze (https://aiopg.readthedocs.io/en/stable/... in se marskiaj drugega. Vec zaokrozenih primerov lahko vidis tudi tule: https://aiohttp-demos.readthedocs.io/en... sicer je vztopna tocka vecinoma HTTP ampak mnogi primeri potem uporabijo asyncio tudi za komunikacijo z drugimi sistemi.

Upam, da ti kaj od tega pride prav. - Srecno
None of us is as dumb as all of us.

jype ::

"CPU bound" pomeni, da procesor počne reči, "I/O bound" pa pomeni, da večino časa čakaš na podatke (z diskov, mreže ali drugod).

Python je zaradi globalnega stanja v interpreterju, ki mora biti zaklenjeno, slab pri prvih in znosen pri drugih rečeh.

Zgodovina sprememb…

  • spremenilo: jype ()


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

Python

Oddelek: Programiranje
203049 (1735) d_DJ
»

[Raptor] Razcep na prafaktorje

Oddelek: Šola
242453 (1995) Math Freak
»

[php] Razbijanje giantskih števil na prafaktorja

Oddelek: Programiranje
332500 (1844) technolog
»

Generatorji praštevil

Oddelek: Znanost in tehnologija
473850 (2754) Phil
»

kako definirtati prastevilo

Oddelek: Programiranje
143792 (3597) ooux

Več podobnih tem