Inom datavetenskap är asynkron I/O en form av icke-blockerande I/O -behandling som gör att en process kan fortsätta att köras utan att vänta på att dataöverföringen ska slutföras .
In- och utdata (I/O) operationer på en dator kan vara ganska långsamma jämfört med databehandling. I/O-enheten kan vara flera storleksordningar långsammare än RAM. Till exempel, under en diskoperation som tar tio millisekunder att slutföra, kan en processor som körs på en gigahertz exekvera tio miljoner behandlingsinstruktionscykler.
Typer av I/O och exempel på Unix I/O-funktioner :
Blockering | icke-blockerande | |
---|---|---|
Synkron | skriva läsa | skriv, läs + poll / välj |
Asynkron | - | aio_skriva, aio_läsa |
Fördelen med icke-blockerande I/O är den effektiva användningen av CPU-resurser. Till exempel i GUI-applikationer kan klassisk blockering av I/O blockera händelseslingan under en lång operation och göra att applikationen inte svarar på användarinteraktion genom att blockera hela exekveringstråden som kör händelseslingan. Dessutom används icke-blockerande I/O i nätverksapplikationer där det är nödvändigt att samtidigt betjäna flera klienter i en exekveringstråd (process). Med ett blockerande tillvägagångssätt skulle bara en "långsam" klient sakta ner hela tråden.
Så vad är skillnaden mellan en asynkron och en synkron metod för icke-blockerande I/O? I det andra fallet undviks blockering genom att kontrollera om det finns inkommande data eller möjligheten att skriva utgående data. I den asynkrona metoden krävs ingen validering. Namnet asynkron betyder att vi "tappar" kontrollen över ordningen på I/O-operationer. Ordningen bestäms av operativsystemet, som bygger operationer baserat på tillgängligheten av I/O-enheter. [ett]
Den asynkrona metoden för att skriva ett program är svårare, men möjliggör större effektivitet. Ett exempel skulle vara att jämföra ett systemanrop epollpå Linux och Överlappad I/O på Microsoft Windows . epollär ett exempel på icke-blockerande synkron I/O och pollar en lista med filbeskrivningar för beredskap att utföra operationer. Det är effektivt för nätverks-I/O eller olika typer av kommunikation mellan processer, eftersom dessa operationer involverar kopiering av data från och till kärnbuffertar och inte förbrukar betydande CPU-tid. Detta systemanrop är dock ineffektivt med långsammare fil-I/O. Till exempel: om det finns några data i filen blockerar läsningen processen tills den läses från disken och kopieras till den medföljande bufferten. Windows-metoden är annorlunda: du anropar funktionen ReadFileoch skickar den en buffert att skriva till och en filbeskrivning. Denna funktion initierar endast en läsoperation och återför omedelbart kontrollen till processen. När operativsystemet i bakgrunden läser data från filen till bufferten kommer det att signalera processen att operationen är klar, antingen genom ReadFile återuppringningen som skickas till funktionen eller genom I/O Completion Port (IOCP). Återuppringningsfunktionen kommer endast att anropas i väntan på att operationen/operationerna ska slutföras. [2]
De typer av API :er som tillhandahålls till applikationen motsvarar inte nödvändigtvis de mekanismer som faktiskt tillhandahålls av operativsystemet, emulering är möjlig.
Tillgänglig på FreeBSD , OS X , VMS och Windows .
Det potentiella problemet är att stackdjupet kan växa okontrollerat, så det extremt viktiga att göra är att bara schemalägga en annan I/O när den föregående har slutförts. Om den måste tillfredsställas omedelbart, "lindar" den initiala återuppringningen inte upp stacken innan nästa anropas. System för att förhindra detta (som t.ex. "mid-ground" schemaläggning av nästa jobb) ökar komplexiteten och minskar produktiviteten. I praktiken är detta dock vanligtvis inget problem, eftersom nästa I/O själv vanligtvis kommer tillbaka så snart nästa I/O har startat, vilket gör att stacken kan "rullas ut". Problemet kan inte heller förhindras genom att undvika ytterligare återuppringningar med hjälp av en kö tills den första återuppringningen kommer tillbaka.
Coroutines (coroutines) låter dig skriva asynkrona program i en synkron stil. Exempel:
Det finns också många bibliotek för att skapa koroutiner (libcoro [3] , Boost Coroutine)
Tillgänglig på Microsoft Windows , Solaris och DNIX . I/O-förfrågningar utfärdas asynkront, men exekveringsmeddelanden tillhandahålls via synkroniseringskömekanismen i den ordning de slutförs. Vanligtvis förknippad med en tillståndsmaskin som strukturerar huvudprocessen ( händelsedriven programmering ), som kanske inte liknar en process som inte använder asynkron I/O eller som använder någon av de andra formerna, vilket gör det svårt att återanvända kod. Det kräver inte ytterligare speciella synkroniseringsmekanismer eller trådsäkra bibliotek, liksom text (kod) och temporära (händelse) strömmar separeras.
Tillgängliga på IBM , Groupe Bull och Unisys stordatorer , I/O-kanaler är designade för att maximera CPU- och bandbreddsanvändning genom att utföra I/O på samprocessorn. Coprocessorn har en DMA ombord , hanterar enhetsavbrott, styrs av CPU:n och avbryter bara huvudprocessorn när den verkligen behövs. Denna arkitektur stöder även så kallade kanalprogram som körs på kanalprocessorn för att göra det tunga lyftet av I/O-aktiviteter och protokoll.
Den stora majoriteten av allmän datorutrustning förlitar sig helt på två metoder för att implementera asynkron I/O: polling och avbrott. Vanligtvis används båda metoderna tillsammans, balansen är starkt beroende av utformningen av hårdvaran och dess nödvändiga egenskaper. ( DMA i sig är inte en annan oberoende metod, det är bara ett sätt med vilket mer arbete kan göras med varje omröstning eller avbrott.)
Enbart polling-system är i allmänhet möjliga, små mikrokontroller (som system som använder PIC ) är ofta byggda på detta sätt. CP/M -system kan också byggas på detta sätt (även om de sällan var det), med eller utan DMA. Dessutom, när bästa möjliga prestanda behövs för endast ett fåtal uppgifter, på bekostnad av eventuella andra potentiella uppgifter, kan polling till och med vara mer lämpligt, eftersom omkostnaderna förknippade med avbrott kan vara oönskade. (Serviceavbrott tar tid och utrymme att lagra åtminstone en del av processorns tillstånd innan det är dags att återuppta den avbrutna uppgiften.)
De flesta datorsystem för allmänna ändamål är starkt beroende av avbrott. Ett system med endast avbrott kan finnas, även om viss polling vanligtvis krävs. Ofta delar flera potentiella avbrottskällor en gemensam avbrottssignallinje, i vilket fall en poll används av enhetsdrivrutinen för att ta reda på den faktiska källan. (Den här gången bidrar det att ta reda på det till försämring av systemavbrottsprestanda. Under årens lopp har mycket arbete lagts ned för att försöka minimera omkostnader i samband med serviceavbrott. Moderna avbrottssystem kan sägas vara långsamma jämfört med vissa väloptimerade , implementeringar av tidigare versioner, men den allmänna ökningen av hårdvaruprestanda har mildrat detta avsevärt.)
Hybrid tillvägagångssätt är möjliga, där ett avbrott kan orsaka att en liten skur av asynkron I/O startar, och avfrågningen görs i själva skuren. Denna teknik är vanlig i höghastighetsenhetsdrivrutiner som nätverk eller disk, där den förlorade tiden för att återgå till uppgiften som körs innan avbrottet är längre än tiden till nästa nödvändiga underhåll. (Den generella I/O-hårdvaran som används idag är starkt beroende av DMA och stora databuffertar för att kompensera för nackdelen med ett relativt långsamt avbrottssystem. Det är vanligt att använda polling inom förarens huvudslinga , vilket kan göra stor genomströmning ( idealiskt är omröstningar alltid framgångsrika när data visas, eller som mest antalet repetitioner är litet).
En gång i tiden var den här typen av hybridmetod vanligt i disk- och nätverksdrivrutiner där det inte fanns någon DMA eller betydande buffringsförmåga. Eftersom förväntade överföringshastigheter var högre än att till och med fyra operationer i en minsta bearbetningscykel (bittest, villkorlig förgrening, hämta och lagra) kunde utföras, är hårdvaran ofta byggd för att automatiskt generera ett vänteläge på I/ O anordning överförs avfrågningsdataberedskap från mjukvaran till hämtningslagerhårdvaran i processorn och därigenom reduceras antalet programcykeloperationer till två. (Använder faktiskt själva processorn som en DMA-exekutor). 6502 -processorn erbjöd ett ovanligt sätt att tillhandahålla tre element i slingan som hanterar uppkomsten av data, eftersom det finns ett hårdvarustift som, när det triggas, ställer in processorns överflödesbit direkt. (Självklart måste stor försiktighet iakttas vid hårdvarudesign för att undvika att omdefiniera överflödesbiten utanför drivrutinen!)
I dessa exempel anses alla tre typer av I/O i Python använda exemplet med läsning. I/O-objekt och funktioner är abstrakta och tjänar endast som exempel.
1. Blockering, synkron:
enhet = IO . öppna () data = enhet . läs () # processen kommer att blockeras tills det finns några data i enhetens utskrift ( data )2. Icke-blockerande, synkron:
enhet = IO . öppen () medan True : is_ready = IO . poll ( device , IO . INPUT , 5 ) # vänta inte mer än 5 sekunder för en möjlighet att läsa (INPUT) från enheten om is_ready : data = device . läs () # processen blockeras inte eftersom vi har sett till att den är läsbar break # break out of the loop else : print ( "det finns inga data i enheten!" )3. Icke-blockerande, asynkron:
ios = IO . IOService () enhet = IO . öppen ( ios ) def inputHandler ( data , err ): "Data närvarohändelsehanterare" om inte fel : print ( data ) enhet . readSome ( inputHandler ) ios . loop () # vänta på slutet av operationen för att anropa nödvändiga hanterare. Om det inte finns fler operationer kommer loopen att återställa kontrollen.Reaktormönstret kan också tillskrivas asynkron :
enhet = IO . öppen () reaktor = IO . Reaktor () def inputHandler ( data ): "Data närvarohändelsehanterare" print ( data ) reactor . sluta () reaktor . addHandler ( inputHandler , enhet , IO . INPUT ) reaktor . run () # startar reaktorn, som kommer att svara på I/O-händelser och anropa nödvändiga hanterare