Asynkroninen ohjelmointi tai asynkronoitu Lyhyesti sanottuna, se on monien nykyaikaisten kielten ominaisuus, jonka avulla ohjelma voi taitaa useita toimintoja odottamatta tai jäämättä jostakin niistä. Se on älykäs tapa käsitellä tehokkaasti tehtäviä, kuten verkko- tai tiedosto I / O, joissa suurin osa ohjelman ajasta kuluu tehtävän päättymiseen.
Harkitse web-kaavintasovellusta, joka avaa 100 verkkoyhteyttä. Voit avata yhden yhteyden, odottaa tuloksia, sitten avata seuraavan ja odottaa tuloksia, ja niin edelleen. Suurin osa ohjelman ajasta kuluu verkon vastauksen odottamiseen, ei todellisen työn tekemiseen.
Async antaa sinulle tehokkaamman tavan: Avaa kaikki 100 yhteyttä kerralla ja vaihda sitten jokaisen aktiivisen yhteyden välillä, kun ne palauttavat tuloksia. Jos yksi yhteys ei tuota tuloksia, vaihda seuraavaan ja niin edelleen, kunnes kaikki yhteydet ovat palauttaneet tietonsa.
Asynkronisyntaksi on nyt Pythonin vakio-ominaisuus, mutta pitkäaikaisilla Pythonistasilla, jotka ovat tottuneet tekemään yhtä asiaa kerrallaan, voi olla vaikeuksia kietoa päätään sen ympärille. Tässä artikkelissa tutkitaan, miten asynkroninen ohjelmointi toimii Pythonissa ja miten se otetaan käyttöön.
Huomaa, että jos haluat käyttää asynkronointia Pythonissa, kannattaa käyttää Python 3.7: ää tai Python 3.8: ta (viimeisin versio tämän kirjoituksen jälkeen). Käytämme Pythonin asynkronisyntaksia ja auttajatoimintoja, jotka on määritelty kyseisissä kieliversioissa.
Milloin asynkronista ohjelmointia käytetään
Paras aika asynkronointiin on yleensä, kun yrität tehdä työtä, jolla on seuraavat ominaisuudet:
- Työn valmistuminen kestää kauan.
- Viive tarkoittaa I / O (levy tai verkko) -toimintojen odottamista, ei laskentaa.
- Työ käsittää monia I / O-operaatioita kerralla, tai yksi tai useampi I / O-toiminto tapahtuu, kun yrität myös suorittaa muita tehtäviä.
Asyncin avulla voit asettaa useita tehtäviä rinnakkain ja toistaa ne tehokkaasti estämättä sovelluksen loppua.
Joitakin esimerkkejä tehtävistä, jotka toimivat hyvin asynkronoinnin kanssa:
- Verkon kaavinta yllä kuvatulla tavalla.
- Verkkopalvelut (esim. Verkkopalvelin tai kehys).
- Ohjelmat, jotka koordinoivat tuloksia useista lähteistä, joiden palauttaminen vie kauan aikaa (esimerkiksi samanaikaiset tietokantakyselyt).
On tärkeää huomata, että asynkroninen ohjelmointi eroaa monisäikeestä tai moniprosessoinnista. Asynkronointitoiminnot suoritetaan kaikki samassa säikeessä, mutta ne perääntyvät tarvittaessa toisilleen, mikä tekee asynkronoinnista tehokkaampaa kuin ketjutus tai moniprosessointi monenlaisiin tehtäviin. (Lisätietoja tästä alla.)
Python asynkronoitu
odottaa
ja asyncio
Python lisäsi äskettäin kaksi avainsanaa, asynkronoitu
ja odottaa
, asynkronointitoimintojen luomiseen. Harkitse tätä komentosarjaa:
def get_server_status (server_addr) # Mahdollisesti pitkään jatkuva operaatio ... return server_status def server_ops () results = [] results.append (get_server_status ('addr1.server') results.append (get_server_status ('addr2.server') return tuloksia
Saman komentosarjan asynkroninen versio - ei toimiva, riittää antamaan meille käsityksen syntaksin toiminnasta - saattaa näyttää tältä.
async def get_server_status (server_addr) # Mahdollisesti pitkään jatkuva operaatio ... return server_status async def server_ops () results = [] results.append (odota get_server_status ('addr1.server') results.append (odota get_server_status ('addr2). palvelin ') palauttaa tulokset
Toiminnot etuliitteellä asynkronoitu
avainsanasta tulee asynkronisia toimintoja, jotka tunnetaan myös nimellä korutiineja. Korutiinit käyttäytyvät eri tavalla kuin tavalliset toiminnot:
- Coroutines voi käyttää toista avainsanaa,
odottaa
, jonka avulla korutiini voi odottaa tuloksia toisesta korutiinista estämättä. Kunnes tulokset palaavatodottaa
ed coroutine, Python vaihtaa vapaasti muiden käynnissä olevien coroutineiden välillä. - Coroutines voi vain soitetaan muilta
asynkronoitu
toimintoja. Jos juoksetserver_ops ()
taiget_server_status ()
sellaisenaan skriptin rungosta, et saa heidän tuloksiaan; saat Python coroutine -objektin, jota ei voida käyttää suoraan.
Joten jos emme voi soittaa asynkronoitu
toimintoja ei-asynkronisista toiminnoista, emmekä voi suorittaa asynkronoitu
toiminnot suoraan, miten niitä käytetään? Vastaus: Käyttämällä asyncio
kirjasto, joka siltoja asynkronoitu
ja loput Pythonista.
Python asynkronoitu
odottaa
ja asyncio
esimerkki
Tässä on esimerkki (jälleen kerran, ei toimiva, mutta havainnollistava) siitä, miten web-kaavintasovellus voidaan kirjoittaa asynkronoitu
ja asyncio
. Tämä komentosarja ottaa luettelon URL-osoitteista ja käyttää useita asynkronoitu
toiminto ulkoisesta kirjastosta (read_from_site_async ()
) ladata ne ja koota tulokset.
tuo asyncio web_scraping_library-tiedostosta tuonti read_from_site_async asynk. def main (url_list): return odota asyncio.gather (* [read_from_site_async (_) for _ in url_list]) urls = ['//site1.com'''//othersite.com', '//uutisivusto.com'] results = asyncio.run (main (urls)) print (results)
Yllä olevassa esimerkissä käytämme kahta yleistä asyncio
toiminnot:
asyncio.run ()
käytetään käynnistämäänasynkronoitu
toiminto koodin ei-asynkronisesta osasta ja käynnistää siten kaikki ohjelman asynkroniset toiminnot. (Näin juoksemmemain ()
.)asyncio.gather ()
vie yhden tai useamman asynkillä koristelun toiminnon (tässä tapauksessa useitaread_from_site_async ()
hypoteettisesta verkkokaaviosta), suorittaa ne kaikki ja odottaa kaikkien tulosten saapumista.
Ajatus tässä on, aloitamme sitten kaikkien sivustojen lukutoiminnon kerralla kerätä tulokset niiden saapuessa (siten asyncio.gather ()
). Emme odota minkään toiminnon päättymistä ennen kuin siirrymme seuraavaan.
Pythonin asynkronointisovellusten komponentit
Olemme jo maininneet, kuinka Python-asynkronointisovellukset käyttävät korutiineja pääainesosana asyncio
kirjasto niiden ylläpitämiseksi. Muutama muu elementti on myös avain Pythonin asynkronisiin sovelluksiin:
Tapahtumasilmukat
asyncio
kirjasto luo ja hallinnoi tapahtumasilmukat, mekanismit, jotka käyttävät korutiineja loppuun saakka. Vain yhden tapahtumasilmukan pitäisi olla käynnissä kerrallaan Python-prosessissa, vain jotta ohjelmoijan olisi helpompi seurata siihen liittyviä asioita.
Tehtävät
Kun lähetät korutiinin tapahtumasilmukkaan käsittelyä varten, voit saada takaisin a Tehtävä
objekti, joka tarjoaa tavan hallita korutiinin käyttäytymistä tapahtumasilmukan ulkopuolelta. Jos sinun on esimerkiksi peruutettava käynnissä oleva tehtävä, voit tehdä sen soittamalla tehtävään .peruuttaa()
menetelmä.
Tässä on hieman erilainen versio site-scraper-komentosarjasta, joka näyttää tapahtumasilmukan ja tehtävät työssä:
Tuo asynsio web_scraping_library-tiedostosta Tuo read_from_site_async-tehtävät = [] async def def (url_list): for n in url_list: task.append (asyncio.create_task (read_from_site_async (n))) tulosta (tehtävät) return odottaa asyncio.gather (* = ['//site1.com','//othersite.com','//newsite.com'] loop = asyncio.get_event_loop () results = loop.run_until_complete (main (URL)) tulosta (tulokset)
Tämä komentosarja käyttää tapahtumasilmukkaa ja tehtäväobjekteja tarkemmin.
-
.get_event_loop ()
menetelmä tarjoaa meille objektin, jonka avulla voimme hallita tapahtumasilmukkaa suoraan lähettämällä asynkroniset toiminnot sille ohjelmallisesti.run_until_complete ()
. Edellisessä komentosarjassa voimme suorittaa vain yhden ylätason asynkronointitoiminnon käyttämälläasyncio.run ()
. Muuten,.run_until_complete ()
tekee tarkalleen mitä se sanoo: Se suorittaa kaikki toimitetut tehtävät, kunnes ne on tehty, ja palauttaa sitten tulokset yhtenä eränä. -
.create_task ()
method vie toiminnon suoritettavaksi, mukaan lukien sen parametrit, ja antaa meille takaisin aTehtävä
objekti ajaa se. Tässä lähetämme kukin URL-osoitteet erillisinäTehtävä
tapahtumasilmukkaan ja tallennaTehtävä
objektit luettelossa. Huomaa, että voimme tehdä tämän vain tapahtumasilmukan sisällä, tsasynkronoitu
toiminto.
Kuinka paljon hallintaa tarvitset tapahtumasilmukkaan ja sen tehtäviin, riippuu siitä, kuinka monimutkainen sovellus on rakentamasi. Jos haluat vain lähettää kiinteitä töitä samanaikaisesti suoritettavaksi, kuten verkkokaavereissamme, et tarvitse paljon hallintaa - vain tarpeeksi töiden käynnistämiseen ja tulosten keräämiseen.
Sitä vastoin, jos luot täysimittaisen verkkokehyksen, haluat paljon paremman hallinnan korutiinien ja tapahtumasilmukan käyttäytymisessä. Saatat joutua esimerkiksi sulkemaan tapahtumasilmukan sulavasti sovelluksen kaatumisen yhteydessä tai suorittamaan tehtäviä langattomasti, jos soitat tapahtumasilmukkaa toisesta säikeestä.
Asynkronointi vs. langoittaminen vs. moniprosessointi
Tässä vaiheessa saatat miettiä, miksi käyttää asynkronointia ketjujen tai moniprosessoinnin sijaan, jotka molemmat ovat olleet pitkään saatavilla Pythonissa?
Ensinnäkin asynkronoinnin ja ketjujen tai moniprosessoinnin välillä on keskeinen ero, riippumatta siitä, kuinka nuo asiat toteutetaan Pythonissa. Async on noin samanaikaisuus, kun taas ketjut ja moniprosessointi ovat noin rinnakkaisuus. Samanaikaisuus tarkoittaa ajan jakamista tehokkaasti useiden tehtävien välillä kerralla - esimerkiksi tarkistamalla sähköpostiosoitteesi odottaessasi rekisteriä ruokakaupassa. Rinnakkaisuuteen liittyy useita agentteja, jotka käsittelevät useita tehtäviä vierekkäin - esimerkiksi, kun ruokakaupassa on avoinna viisi erillistä rekisteriä.
Async on suurimmaksi osaksi hyvä ketjutuksen korvike, koska ketjutetaan Pythonissa. Tämä johtuu siitä, että Python ei käytä käyttöjärjestelmän ketjuja, vaan omia yhteistyöketjuja, joissa tulkkissa on aina vain yksi ketju kerrallaan. Async tarjoaa yhteistyökierteisiin verrattuna joitain keskeisiä etuja:
- Asynkronitoiminnot ovat paljon kevyempiä kuin langat. Kymmenillä tuhansilla samanaikaisesti käynnissä olevilla asynkronisilla operaatioilla on paljon vähemmän yleiskustannuksia kuin kymmenillä tuhansilla säikeillä.
- Asynkronikoodin rakenteen avulla on helpompi päättää, mistä tehtävät nousevat ja loppuvat. Tämä tarkoittaa, että tietokilpailuissa ja langan turvallisuudessa ei ole merkitystä. Koska kaikki asynkronisen tapahtumasilmukan tehtävät suoritetaan yhdessä ketjussa, Python (ja kehittäjä) on helpompi sarjoittaa, miten ne käyttävät muistissa olevia objekteja.
- Asynkronointitoiminnot voidaan peruuttaa ja käsitellä helpommin kuin ketjut.
Tehtävä
esine, josta palaammeasyncio.create_task ()
tarjoaa meille kätevän tavan tehdä tämä.
Toisaalta moniprosessointi Pythonissa on parasta töille, jotka ovat voimakkaasti suorittimen eikä I / O-sidottuja. Async toimii itse asiassa käsi kädessä moniprosessoinnin kanssa, kuten voit käyttää asyncio.run_in_executor ()
siirtää CPU-intensiivisiä töitä prosessiryhmään keskitetystä prosessista estämättä sitä.
Seuraavat vaiheet Python-asynkronoinnilla
Paras tehtävä on rakentaa muutama yksinkertainen oma asynkronointisovellus. Hyviä esimerkkejä on nyt runsaasti, kun Pythonin asynkroninen ohjelmointi on käynyt läpi muutaman version, ja sillä on ollut pari vuotta aikaa asettua alas ja tulla yleisemmäksi. Viralliset asiakirjat asyncio
on lukemisen arvoinen nähdäksesi, mitä se tarjoaa, vaikka et aio käyttää kaikkia sen toimintoja.
Saatat myös tutkia asynkronoitujen kirjastojen ja väliohjelmistojen kasvavaa määrää, joista monet tarjoavat asynkronisia, estämättömiä versioita tietokantaliittimistä, verkkoprotokollista ja vastaavista. aio-libs
arkistossa on joitain keskeisiä, kuten aiohittp
kirjasto verkkoon pääsyä varten. On myös syytä etsiä kirjastoja Python Package Index -hakemistosta asynkronoitu
avainsana. Asynkronisen ohjelmoinnin kaltaisella tavalla paras tapa oppia on nähdä, miten muut ovat panneet sen käyttämään.