Кіріспе
Кіріс/шығыс өңдеу түрі
Компьютерлік ғылымда асинхронды I/O (сондай-ақ ретті емес I/O) – I/O операциясы аяқталғанға дейін басқа өңдеуді жалғастыруға мүмкіндік беретін кіріс/шығыс өңдеу түрі. Windows API-де асинхронды I/O үшін қолданылатын атау – I/O-ның үстінен жабысуы. Компьютердегі кіріс-шығыс (I/O) операциялары деректерді өңдеумен салыстырғанда өте баяу болуы мүмкін. I/O құрылғысына физикалық түрде қозғалуы тиіс механикалық құрылғылар кіре алады, мысалы, оқу немесе жазу үшін жол іздейтін қатты диск; бұл көбінесе электр тогының ауысуынан әлдеқайда баяу. Мысалы, дискіде он миллисекундқа созылатын операция кезінде бір гигагерц жиілікте жұмыс істейтін процессор он миллион нұсқаулық өңдеу циклын орындай алады. I/O-ға қарапайым тәсіл – кіруді бастау және оның аяқталуын күту. Бірақ синхронды I/O немесе I/O блоктау деп аталатын мұндай тәсіл, байланыс жүргізіліп жатқанда бағдарламаның ілгерілеуін тоқтатады, жүйе ресурстарын бос қалдырады. Бағдарлама көптеген I/O операцияларын орындағанда (мысалы, бағдарлама негізінен немесе көбінесе пайдаланушының енгізуіне байланысты), процессор I/O операцияларының аяқталуын күтіп, уақытының көп бөлігін бекер өткізе алады. Сонымен қатар, байланысты бастау және кейін I/O аяқталуын талап етпейтін өңдеуді орындау мүмкін. Бұл тәсіл асинхронды кіріс/шығыс деп аталады. I/O аяқталуына байланысты кез келген тапсырма (бұл кіріс мәндерін пайдалануды және жазу операциясы аяқталғанын растайтын маңызды операцияларды қамтиды) әлі де I/O операциясын аяқтауын күтуі керек, сондықтан бұғатталған болып қалады, бірақ I/O операциясына тәуелді емес басқа өңдеу жалғаса алады. Көптеген деңгейде асинхронды I/O-ны іске асыру үшін көптеген операциялық жүйе функциялары бар. Шын мәнінде, барлық операциялық жүйелердің ең негізгі функцияларының бірі – кем дегенде, негізгі асинхронды I/O түрін орындау, бірақ бұл пайдаланушы немесе бағдарламашы үшін айқын болмауы мүмкін. Ең қарапайым бағдарламалық шешімде аппараттық құрылғының жағдайы оның келесі операцияға дайындығын анықтау үшін үнемі тексеріледі. (Мысалы, CP/M операциялық жүйесі осылай құрылған. Оның жүйелік шақыру семантикасы бұдан да күрделі I/O құрылымын қажет етпеді, бірақ көптеген іске асырулар күрделірек және тиімдірек болды.) Тікелей жадқа қол жеткізу (DMA) дауыс беру жүйесінің тиімділігін арттырады, ал аппараттық үзілістер дауыс беруді толығымен жоюға мүмкіндік береді. Көп тапсырмалы операциялық жүйелер аппараттық үзілістермен қамтамасыз етілген функционалдылықты пайдалана алады, сонымен бірге үзілістерді басқарудың күрделілігін пайдаланушыдан жасырады. Spooling – асинхронды I/O-ны пайдалану үшін жасалған көп тапсырмалы жұмыстың алғашқы түрлерінің бірі. Соңында, пайдаланушы процестеріндегі көптіріктілік және айқын асинхронды I/O API қосымша бағдарламалық жасақтама күрделілігі есебінен асинхронды I/O-ны одан әрі пайдалана алады. Асинхронды I/O энергия тиімділігін және кейбір жағдайларда өнімділікті жақсарту үшін қолданылады. Алайда, кейбір жағдайларда ол кідіріс пен өнімділікке кері әсерін тигізуі мүмкін.
Процесс
Unix-тің алғашқы нұсқаларында қолжетімді. Көп тапсырмалы операциялық жүйеде өңдеу әртүрлі процестерге таратылуы мүмкін, олар тәуелсіз жұмыс істейді, өз жадына ие және өздерінің I/O ағындарын өңдейді; мұндай ағындар көбінесе құбырлар арқылы байланысады. Процестерді құру және қолдау өте қымбат болғандықтан, бұл шешім процестер жиынтығы кішкентай және салыстырмалы түрде тұрақты болған жағдайда ғана тиімді. Сондай-ақ, жеке процестер бір-бірінің I/O ағындарын өңдеуден басқа тәуелсіз жұмыс істей алады деп есептеледі; егер олар басқа тәсілдермен байланысуы керек болса, оларды үйлестіру қиындық тудыруы мүмкін. Бұл тәсілдің кеңейтілген түрі – дерек ағыны бағдарламалау, ол құбырлар қолдайтын тізбектерге қарағанда күрделірек желілер құруға мүмкіндік береді.
Select (/ poll) бұрандалары
BSD Unix-те және BSD іске асырудан кейін пайдаланған немесе үлгіленген TCP/IP протоколы бар кез келген басқа да жүйеде қолжетімді. Сауалнама тақырыбының бір түрі ретінде, select циклы select жүйелік шақыруды пайдаланып, файл дескрипторында жағдай туғанға дейін (мысалы, оқуға деректер келгенде), белгілі бір уақыт өткенде немесе сигнал алынғанда (мысалы, бағынышты процесс аяқталғанда) күту режиміне көшеді. Select шақыруының қайтарым параметрлерін қарап, цикл қай файл дескрипторы өзгергенін анықтап, тиісті кодты орындайды. Әдетте, пайдаланудың ыңғайлылығы үшін select циклы оқиға циклы ретінде іске асырылады, мүмкін callback функцияларын қолдана отырып; мұндай жағдай оқиғаларға негізделген бағдарламалауға өте қолайлы. Бұл әдіс сенімді және салыстырмалы түрде тиімді болғанымен, ол Unix парадигмасына – «барлығы файл» деген қағидаға көп тәуелді. Файл дескрипторын қатыстырмайтын I/O операциялары процесті тоқтата алады. Select циклы сондай-ақ барлық I/O операцияларын орталық select шақыруына біріктіруге қабілетті болуға байланысты; өз I/O операцияларын жүзеге асыратын кітапханалар бұл жағынан қиындық тудыруы мүмкін. Тағы бір әлеуетті мәселе – select және I/O операцияларының жеткілікті деңгейде байланыспауы, нәтижесінде select нәтижесі жалған болуы мүмкін: егер екі процесс бір файл дескрипторынан оқыса (дизайннің нашарлығы), select оқуға деректердің бар екенін көрсетуі мүмкін, бірақ оқу операциясы орындалған кезде деректер жоғалып кеткен болуы мүмкін, соның салдарынан процесс тоқтап қалады; егер екі процесс бір файл дескрипторына жазса (бұл жиі кездеседі), select дереу жазуға болатындығын көрсетуі мүмкін, бірақ жазу операциясы бұрынғы процесс буферді толтырғандықтан немесе жазу буфердің көлемінен асып кеткендіктен немесе алушыға сәйкес келмегендіктен тоқтап қалуы мүмкін. Select циклы, мысалы, аяқталу тізімі әдісімен қол жеткізілетін жүйенің ең жоғары тиімділігіне жете алмайды, себебі select шақыруының семантикасы, қабылданатын оқиғалар жиынтығын әр шақыруда өзгертуге мүмкіндік береді, таңдау массивін қарап шығу үшін белгілі бір уақыт жұмсайды. Бұл бір файл дескрипторын терезелік жүйе үшін және бірнеше ашық файлдар үшін ашатын пайдаланушы бағдарламалары үшін аз жүктеме тудырады, бірақ әлеуетті оқиға көздерінің саны артқан сайын проблемаға айналады және көптеген клиент-сервер бағдарламаларын жасауға кедергі келтіруі мүмкін, мысалы, C10k мәселесінде; басқа асинхронды әдістер мұндай жағдайларда айтарлықтай тиімді болуы мүмкін. Кейбір Unix жүйелері жүйеге арналған шақыруларды ұсынады, олар жақсы масштабталуға мүмкіндік береді; мысалы, Linux-тағы epoll (қайтарылатын таңдау массивін тек оқиға болған оқиға көздерімен ғана толтырады), FreeBSD-дегі kqueue және Solaris-тегі оқиға порттары (және /dev/poll). SVR3 Unix poll жүйелік шақыруын қамтамасыз етті. Бұл талқылау үшін select-ке қарағанда жақсы атау, бірақ олар негізінен бірдей нәрсе. SVR4 Unix (және осылайша POSIX) екі шақыруды да ұсынады.
Сигналдар (бұзылулар)
BSD және POSIX Unix жүйелерінде қолжетімді. Кіріс-шығыс асинхронды түрде жүзеге асырылады және оның аяқталуымен сигнал (үзіліс) туындайды. Төменгі деңгейдегі ядролық бағдарламалау сияқты, сигналды өңдеушіде қауіпсіз пайдалануға арналған мүмкіндіктер шектеулі, ал процесс ағыны кез келген сәтте үзілуі мүмкін, нәтижесінде сигналды өңдеушіге дерек құрылымдары тұрақсыз көрінеді. Сигналды өңдеуші әдетте өздігінен қосымша асинхронды кіріс-шығыс операцияларын жүзеге асыра алмайды. Сигналдық тәсіл операциялық жүйеде салыстырмалы түрде оңай іске асырылса да, қолданба бағдарламасына операциялық жүйенің ядролық үзіліс жүйесін жасаумен байланысты қосымша қиындықтарды әкеледі. Оның ең жаман қасиеті – әрбір тоқтау (синхронды) жүйелік шақыру үзілуге ұшырауы мүмкін; бағдарламашы әдетте әр шақыру үшін қайталау кодын енгізуі қажет.
Қайта шақыру функциялары
Классикалық Mac OS, VMS және Windows жүйелерінде қолжетімді. Сигнал әдісінің көптеген ерекшеліктерін мұралайды, себебі ол негізінен соған ұқсас, бірақ көбінесе осылай танылмайды. Ерекшелігі, әрбір I/O сұранысының әдетте өзіндік аяқталу функциясы болуы мүмкін, ал сигнал жүйесінде тек бір ғана қайта шақыру болады. Дегенмен, кері шақыруларды пайдаланудың потенциалды мәселесі – стек тереңдігі басқарылмайтын деңгейде өсуі мүмкін, себебі бір I/O операциясы аяқталғанда, екіншісін жоспарлау өте жиі кездеседі. Егер бұл талап дереу орындалса, келесі шақыру шақырылғанға дейін алғашқы кері шақыру стекте «ашылмай» қалады. Мұны болдырмау үшін жасалған жүйелер (мысалы, жаңа жұмысты «орталық» кестелеу) күрделілікті арттырып, өнімділікті төмендетеді. Бірақ, практикада бұл көбінесе мәселе тудырмайды, өйткені жаңа I/O операциясы жаңа I/O басталысымен бірге дереу қайта оралады, бұл стекке «еркін оралуға» мүмкіндік береді. Бұл мәселені кезек пайдалану арқылы, алғашқы кері шақыру аяқталғанға дейін қосымша кері шақырулардан аулақ болу арқылы да болдырмауға болады.
Жеңіл процестер немесе жіктер
Жеңіл салмақты процестер (ЖЖП) немесе жіптер қазіргі заманғы операциялық жүйелердің көпшілігінде қолжетімді. Процесс әдісіне ұқсас, бірақ төменгі жүктемемен және ағындарды үйлестіруге кедергі келтіретін деректерді оқшаулаусыз. Әрбір ЖЖП немесе жіп өзі бағдарламалау логикасын жеңілдететін дәстүрлі блоктау синхронды I/O-ны пайдаланады; бұл Java және Rust сияқты көптеген бағдарламалау тілдерінде қолданылатын кең таралған үлгі. Көп жіптілікте ядро ұсынған синхрондау механизмдері мен жіпке қауіпсіз кітапханаларды пайдалану қажет. Бұл әдіс веб-серверлер сияқты өте кең ауқымды қолданбалар үшін тиімді емес, себебі көптеген жіптер қажет болады. Бұл тәсіл Erlang бағдарламалау тілінің жұмыс уақытында да қолданылады. Erlang виртуалды машинасы миллионға дейін Erlang процесінен I/O-ны өңдеу үшін аз ғана жіптер немесе кейде бір ғана процесс кішкентай тобын пайдаланып, асинхронды I/O-ны қолданады. Әрбір процесте I/O-мен жұмыс істеу көбінесе блоктау синхронды I/O арқылы жазылады. Осылайша асинхронды I/O-ның жоғары өнімділігі мен қалыпты I/O-ның қарапайымдылығы біріктіріледі (мысалы, Actor моделі). Erlang-тағы көптеген I/O мәселелері хабар алмасуға бейімделеді, оны енгізілген таңдамалы қабылдау арқылы оңай өңдеуге болады. Fibers / Coroutines Erlang процестерімен салыстырылатын кепілдіктер бермесе де, Erlang жұмыс уақытынан тыс асинхронды I/O-ны жүзеге асырудың ұқсас жеңіл тәсілі ретінде қарастырылуы мүмкін.
Толықтыру кезектері/порттар
Microsoft Windows, Solaris, AmigaOS, DNIX және Linux-та қолжетімді (io uring пайдаланылады, 5.1 және одан жоғары нұсқаларында қолжетімді). I/O сұраулары асинхронды түрде жіберіледі, бірақ олардың аяқталу ретімен синхронды кезек механизмі арқылы аяқталғаны туралы хабарламалар беріледі. Әдетте, негізгі процестің (оқиға басқарылатын бағдарламалау) күй машинасы құрылымымен байланысты, бұл асинхронды I/O қолданбайтын немесе басқа формаларды пайдаланатын процестен өте өзгеше болуы мүмкін, соның салдарынан кодты қайта пайдалану қиынға түседі. Қосымша арнайы синхрондау механизмдері немесе жиекке қауіпсіз кітапханалар қажет емес, сондай-ақ код және оқиға ағындары да бөлек емес.
Іс-шара жалаушалары
VMS және AmigaOS жүйелерінде қолжетімді (көбінесе аяқталу портымен бірге пайдаланылады). Бұл толтыру кезегі әдісінің көптеген ерекшеліктерін мұралайды, себебі ол негізінен бір тереңдігі бар толтыру кезегі болып табылады. Кезек "тереңдігі" әсерін имитациялау үшін әрбір өңделмеген (бірақ аяқталған) оқиғаға қосымша оқиға белгісі қажет, әйтпесе оқиға туралы мәліметтер жоғалуы мүмкін. Мұндай жиынтықтағы келесі қолжетімді оқиғаны күту үшін, үлкен мөлшердегі параллель оқиғаларға жақсы масштабтала бермейтін синхронизация механизмдері қажет.
I/O арнасы
IBM, Groupe Bull және Unisys компанияларының негізгі компьютерлерінде қолжетімді. I/O арнасы CPU-дың пайдалануын және өнімділігін арттыру үшін, көп бөлігін қосымша процессорға (coprocessor) жүктеу арқылы жасалған. Қосымша процессорда тікелей жадқа қол жеткізу (DMA) мүмкіндігі бар, ол құрылғыдан келетін сигналдарды өңдейді, негізгі процессормен басқарылады және тек қана қажет болған жағдайда ғана негізгі процессорды тоқтатады. Бұл архитектура сонымен қатар I/O операциялары мен протоколдары үшін ауыр жүк көтеруге арналған арна бағдарламаларын қолдайды, олар арна процессорында жұмыс істейді.
Тіркелген I/O
Windows Server 2012 және Windows 8 нұсқаларында қолжетімді. Үлкен көлемде шағын хабарламаларды өңдейтін қосымшалар үшін оңтайландырылған, бұл джиттер мен жауап уақытын азайту арқылы секундына I/O операцияларының санын арттыруға мүмкіндік береді.
Іске асыру
Жалпы мақсаттағы есептеу аппараттарының басым көпшілігі асинхронды I/O-ны жүзеге асырудың екі әдісіне толықтай сүйенеді: сауалнама және үзілістер. Әдетте екі әдіс те бірге қолданылады, арақатынасы аппараттық құрылғының дизайнына және оның қажетті өнімділік сипаттамаларына күрт тәуелді. (DMA өзі жеке тәуелсіз әдіс емес, ол бір сауалнама немесе үзіліс арқылы көбірек жұмыс атқару құралы ғана.) Таза сауалнама жүйелері мүмкін, кішкентай микроконтроллерлер (мысалы, PIC негізіндегі жүйелер) көбінесе осылай жасалады. CP/M жүйелері де осылай құрылуы мүмкін (бірақ көбінесе солай болмайды), DMA болсын, болмасын. Сондай-ақ, егер басқа тапсырмалардың барлығынан бас тартып, тек бірнеше тапсырма үшін максималды өнімділік қажет болса, сауалнама да орынды болуы мүмкін, себебі үзілістерді қабылдаудың қосымша шығындары ыңғайсыз болуы мүмкін. (Үзіліске жауап беру үшін процессор күйінің кем дегенде бір бөлігін сақтауға уақыт [және жад] керек, сондай-ақ үзіліске ұшыраған тапсырманы қайта бастауға уақыт кетеді.) Көптеген жалпы мақсаттағы есептеу жүйелері үзілістерге көп сүйенеді. Таза үзіліс жүйесі де мүмкін, бірақ көбінесе сауалнаманың да бір бөлігі қажет, өйткені үзілістердің бірнеше мүмкін көздері бір үзіліс желісін бөлісуі жиі кездеседі, мұндай жағдайда құрылғы драйвері нақты көзді анықтау үшін сауалнаманы пайдаланады. (Бұл анықтау уақыты үзіліс жүйесінің өнімділігін төмендетуге әсер етеді. Ыңғайлылық үшін үзіліске жауап беруге байланысты шығындарды азайту үшін жылдар бойы көп жұмыс істелді. Қазіргі үзіліс жүйелері кейбір жақсырақ бұрынғы жүйелермен салыстырғанда өте жай, бірақ аппараттық өнімділіктің жалпы өсуі бұл мәселені жеңілдетті.) Гибридтік тәсілдер де мүмкін, онда үзіліс асинхронды I/O-ның бірнеше блогын бастай алады, ал блоктердің ішінде сауалнама қолданылады. Бұл әдіс жоғары жылдамдықты құрылғы драйверлерінде, мысалы, желілік немесе дискілік драйверлерде жиі қолданылады, онда үзіліске дейінгі тапсырмаға оралуға кеткен уақыт келесі қызмет көрсетуге қажетті уақыттан артық. (Қазіргі I/O жабдықтары салыстырмалы түрде нашар өнімді үзіліс жүйесін толықтыру үшін DMA және үлкен дерек буферлерін кеңінен пайдаланады. Бұл жүйелер драйвер циклдерінің ішінде сауалнаманы қолданады және үлкен өнімділікті көрсете алады. Идеалды жағдайда, әр дерек бойынша сауалнамалар әрқашан сәтті аяқталады немесе ең көп дегенде бірнеше рет қайталанады.) Бір кезде бұл гибридтік тәсіл дискілік және желілік драйверлерде кең таралған, онда DMA немесе маңызды буферлеу болмаған. Қажетті деректерді беру жылдамдығы тіпті ең төменгі төрт операциялық циклдан (бит тесті, өзіне шартты өту, алу және сақтау) жылдам болғандықтан, аппараттық жабдық көбінесе I/O құрылғысында автоматты күту күйін жасаумен жасалған, деректер дайын сауалнамасын бағдарламалық жасақтамадан процессордың алу немесе сақтау аппараттарына көшіріп, бағдарламалық циклды екі операцияға дейін қысқартқан. (Дәлі, процессорды DMA машинасы ретінде пайдалану.) 6502 процессоры дерек бойынша үш операциялық циклді қамтамасыз етудің ерекше мүмкіндігін ұсынды, өйткені оның аппараттық тірегі болған, ол белсенді болғанда процессордың Overflow битін тікелей орнатуға мүмкіндік берді. (Әрине, құрылғы драйверінің сыртында Overflow битін жаңсыртудан сақтану үшін аппараттық жобалауда ерекше сақтық қажет!)
Синтез
Тек осы екі құралды (сауалнама және үзілістер) пайдаланып, жоғарыда талқыланған асинхронды I/O-ның барлық басқа түрлері синтезделуі мүмкін (және шындығында да синтезделеді). Java виртуалды машинасы (JVM) сияқты ортада асинхронды I/O синтезделуі мүмкін, тіпті JVM жұмыс істейтін орта оны мүлдем ұсынбауы мүмкін. Бұл JVM-нің интерпретациялық табиғатына байланысты. JVM бақылау ағынын ішкі түрде өзгерту үшін мерзімді түрде сауалнама жасауға (немесе үзіліс күтуге) болады, соның салдарынан бірнеше бір уақытта іске қосылған процестер пайда болады, олардың кем дегенде бірі асинхронды I/O-ны орындау үшін қажет. (Әрине, микроскопиялық деңгейде параллелизм өте жоғары болуы мүмкін және кейбір идеалды емес қасиеттерін көрсетуі мүмкін, бірақ сырттай көрінісі қалағандай болады.) Шындығында, асинхронды I/O-ның басқа түрін синтездеу үшін сауалнаманы кез келген түрінде пайдаланудың мәселесі осында. Сауалнама болып табылатын әрбір CPU циклы босқа кетеді, қажетті міндетті орындаудың орнына қосымша шығындарға жұмсалады. Сауалнама емес әрбір CPU циклы күтіп тұрған I/O-ға жауап беру уақытының ұзаруын білдіреді. Осы екі қарама-қарсы күштің арасында қанағаттанарлық тепе-теңдік табу қиын. (Дәл осы себепті аппараттық үзіліс жүйелері ойлап табылды.) Тиімділікті арттырудың кілті – тиісті қолданбаны ояту үшін үзіліс қабылданған кезде жасалатын жұмыстың мөлшерін азайту. Екінші жағынан (бірақ кем емес маңыздысы) – қолданбаның өзіне не істеу керектігін анықтау үшін қолданатын әдіс. Әсіресе (қолданба тиімділігі үшін) проблемалық болып табылады ашық сауалнама әдістері, соның ішінде таңдау/сауалнама механизмдері. Олардың қызығушылығын тудыратын I/O оқиғалары үзіліс арқылы туындаса да, осы механизмбен өзара әрекеттесу сауалнама арқылы жүзеге асырылады және сауалнама кезінде көп уақыт жұмсалуы мүмкін. Бұл әсіресе таңдау (және сауалнама) арқылы мүмкін болатын кең ауқымды сауалнамаға қатысты. Үзілістер Сигналдарға, Кері шақыру функцияларына, Аяқталу кезектеріне және Оқиға туларына өте жақсы сәйкес келеді, мұндай жүйелер өте тиімді болуы мүмкін.