[so] I/O

Razvan Deaconescu razvan.deaconescu at cs.pub.ro
Thu Jul 31 11:38:31 EEST 2008


On Thu, 2008-07-31 at 09:02 +0300, Alexandru Goia wrote:
> Buna ziua,
> 
> In ce situatii e recomandat sa fac blocking I/O (read, write) si in ce 
> situatii e mai bine sa fac non-blocking I/O ? (Nu ma refer la 
> multiplexed I/O.) Va rog, daca se poate, cu exemple concrete.

=== Warning! Huge message below! ===

In primul rand exista o diferenta intre non-blocking I/O si asynchronous
I/O.
* O operatie I/O non-blocanta (pe un descriptor de socket sau fisier
marcat ca operand in mod non-blocant) se va intoarce imediat stocand in
buffer cat a avut disponibil in acel moment.
* O operatie I/O asincrona se va intoarce imediat dar va fi planificata
de un subsistem specializat. Procesul va fi notificat de incheierea
operatiei asincrone prin diverse mecanisme (semnale, multiplexed I/O,
eventfd etc.).

Operatiile de tipul overlapped din Windows[1] sunt operatii asincrone.
Adica se transmite comanda de executat (citire/scriere, buffer,
dimensiune buffer, descriptor), se intoarce imediat, dar in spate se
planifica aceasta operatie, iar procesul va fi notificat in momentul
incheierii operatiei.

De mare ajutor este matricea de modele I/O[2] cu explicatiile auxiliare.

Revenind acum la intrebarea ta. In principiu, operatiile sincrone sunt
potrivite pentru cea mai mare parte a aplicatiilor pentru ca asigura
secventialitate. Astfel, daca vrei sa faci prelucrari asupra unei bucati
dintr-un fisier, apelezi o functie blocanta si astepti incheierea ei. La
intoarcerea functiei vei avea in buffer bucata de fisier dorita si vei
putea face prelucrari peste aceasta.

Singurul dezavantaj este, sa spunem asa, paralelismul. Astfel, daca o
aplicatie foloseste simultan 5, 10, 100, 1000, 10000 de descriptori de
fisier si face si alte prelucrari simultan, va trebui sa apeleze pe rand
functii blocante pentru fiecare fisier. Asta inseamna ca se va bloca la
un descriptor de fisier in timp ce altele pot fi citite/scrise. Se
pierde din productivitate (throughput).

O solutie este delagarea unui thread care sa se ocupe de fiecare
descriptor de fisier. Modelul multithreaded este folosit de multe
servere in special cele scrise in Java. Dezavantajul modelului
multithreaded este scalabilitatea. Nu poti satisface in mod scalabil mii
de cereri simultane folosind un thread per descriptor[3].

Alternativa este folosirea mecanismelor event-based[4], in care exista
un punct central in cod unde procesul este notificat de incheierea unei
operatii sau faptul ca un descriptor poate fi citit/scris. Aici intra
primitivele de tip multiplexed I/O (select, epoll, iocp, eventfd).

Primitivele event-based notifica pregatirea unui descriptor pentru
operatii de citire/scriere. Dupa ce ai fost notificat, inca vei putea sa
te blochezi printr-un read/write pe acel descriptor. Ca sa nu se
intample acest lucru vei folosi operatii asincrone sau operatii
non-blocante.

In Linux nu se pot folosi (inca) operatii asincrone pe socketi, probabil
datorita faptului ca socketii urmeaza un model stream de citire a
datelor in timp ce pe fisiere se poate face seek. Astfel, dupa ce ai
fost notificat ca un socket este pregatit de citire/scriere, vei face o
operatie non-blocanta pe acel socket (adica socketul va fi fost
configurat in modul non-blocant) si apoi vei reveni in punctul central
de multiplexare I/O. Pe fisiere, pentru a nu te bloca, poti folosi
operatii asincrone si va trebui sa reusesti sa fii notificat in acelasi
punct central. Incepand cu versiunea 2.6.22 de nucleu, interfata
eventfd[5] permite acest lucru.

In Windows, dupa cum am spus, nu exista operatii non-blocante, doar
asincrone[1]. Dupa ce vei fi notificat ca un descriptor/handle poate fi
scris/citit vei putea comanda o noua operatie asincrona si apoi astepta
in punctul central (I/O Completion Port[6]) incheierea acelei operatii.

Ca sa conchid (pe cat se poate), in general vei folosi operatii
blocante/sincrone. Trecerea la operatii asincrone sau non-blocante se
face in momentul in care trebuie sa satisfaci simultan mai multe cereri:
de exemplu in cazul serverelor cu multe conexiuni sau alte aplicatii
care interactioneaza foarte des cu multe fisiere.

In momentul in care ai nevoie de modelul event-based si de operatii
asincrone va trebui sa faci o investigare a platformei pe care lucrezi
pentru a vedea care sunt primitivele oferite si care sunt cele mai
potrivite mecanisme pentru problema ta. Spre exemplu, daca pana acum
ceva vreme programarea pe Java a unui server web impunea folosirea
mecanismelor multi-threaded, noul model de I/O[7] permite folosirea de
primitive de tipul multiplexed/non-blocking I/O care asigura
scalabilitatea serverelor.

Daca vrei sa aprofundezi aceste aspecte, dincolo de link-urile
prezentate de mine, sunt multe pagini utile in Internet care sa te ajute
(key words: synchronous I/O, asyncrhonous I/O, event-based, multiplexed
I/O). De asemenea, foarte util este browsing-ul prin codul sursa al
diverselor servere web/ftp care folosesc mecanisme performante de
asigurare a scalabilitatii. Nu in ultimul rand, comunitatea Usenet iti
poate fi de folos[8][9].

Imi pare rau ca raspunsul nu este atat de scurt pe cat (probabil) ai fi
dorit. Nu cunosc suficient de bine domeniul asynchronous/multiplexed I/O
cat sa-ti dau un raspuns simplu[10] :-)

Razvan

[1] http://msdn.microsoft.com/en-us/library/aa365683(VS.85).aspx
[2] http://www.ibm.com/developerworks/linux/library/l-async/index.html
[3] http://www.kegel.com/c10k.html
[4] http://en.wikipedia.org/wiki/Event-driven_programming
[5] http://www.kernel.org/doc/man-pages/online/pages/man3/eventfd_read.3.html
[6] http://msdn.microsoft.com/en-us/library/aa365198(VS.85).aspx
[7] http://en.wikipedia.org/wiki/New_I/O
[8] http://groups.google.com/group/comp.unix.programmer/topics
[9] http://groups.google.com/group/comp.programming/topics
[10] http://www.quoteworld.org/quotes/4082


-- 
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.



More information about the so mailing list