Komentar k predchozimu clanku

13.01.2004 08:44 | blackhole

Puvodne to mel byt komentar ale je to prilis dlouhe

predstavte si napr. ze chcete udelat rychlou obsluhu nejakeho diskoveho zarizeni. ja bych to udelal takto (nerikam ze je to idealni, nejsem expert na tyto veci - navic ruzne pojmy pouzivam volne, tj. kdyz rikam thread mam tim na mysli semantiku objektu ne to co dostane pri pthread_create(), pojem stream pouzivam ve smyslu data-flow programovani, ne oop): diskove zarizeni ma N nezavislych disku, M radicu a 1 buffer (nevidim duvod proc to komplikovat) vytvorime M threadu obluhujicich cteni z disku, pro idealni rozlozeni dat je nutne sesynchronizovat disky a udelat nejakou formu prokladani a to s ohledem na fyzicke rozlozeni dat tak i na vyuziti radicu. nevim jak by se to resilo, ale je jiste ze by myselo existovat N bufferu pro disky, ktere by se kombinovaly do M bufferu radicu a konecne do vystupniho bufferu, ktery by byl z vnejsku vniman jako stream. Pro zajisteni optimalniho vykonu by bylo dobre delat synchronizaci threadu nejak inteligentne. Videl bych to asi takto: (jazyk v kterem to pisu NENI C!) <? struct buff { dynamically_sized_array data; /* where to store data */ guard guard; /* protection */ function protector = protector; } buffer; /* asynchronous protector of each data zone * automagically called on when some zone is accessed * notifies all the involved threads */ function protector { td = current; forever_spin { /* marks the zone as torn */ td->pre_split (lambda (pick_the_one) (d_unlambda buffer.data)); /* protect the new zone */ td->protect (lambda (pick_the_one) (d_unlambda buffer.data)); /* actually tears it */ td->post_split (lambda (pick_the_one) (d_unlambda buffer.data)); put_to_pool (new_thread); assign (new_thread, (lambda (pick_the_one) (d_unlambda buffer.data))); if (action == WRITE) for_each_involved_thread (lambda (pick_the_one) (d_unlambda buffer.data)); td_g->reread (that_zone); } } /* buffer zones merger - transparently called on finished job */ function finished { merge (lambda (map_fun_parm (pick_the_one ++ next (pick_the_one))) (d_unlambda buffer.data)); } /* quite complex to develop now ;) */ function pick_the_one { return the_one; /* something */ } function set_protection { atomic_set (lambda (pick_the_one) (d_unlambda buffer.guard)); } /* writes to buffer data read from MULTIPLE disks/controllers * part of read() function - dont get confused by the name! */ function write_to_buff { /* when someone accesses some part of data we * tear it protecting just the part we write to */ set_protection (lambda (pick_the_one) (d_unlambda buffer.data)); corotounize by (lambda (x) (disk_slices DISK_X)) { simple_write (read_data, lambda (pick_the_one) (d_unlambda buffer.data)); } } function schedule_threads { iterate (number (d_unlambda buffer.data)) { put_to_pool (new_thread); assign (new_thread, (lambda (pick_the_one) (d_unlambda buffer.data)) } } /* read function itself */ function read { /* schedule threads according to data layout */ schedule_threads(); for_each_thread_in_pool (td) { td->write_to_buff (lambda (pick_the_one) (d_unlambda (buffer.data))); } if (flags == SYNC) spin_until_done return (d_lambda (buffer.data)); } /* lambda abstraction for data - transparent merging of data areas */ functor d_lambda (x -> [a1....an]) /* transparent merging of data areas */ functor d_unlambda ([a1..an] -> x) ?> v principu to vypada takto: mame homogeni pole buffer.data, ktere je rozdeleno na zony do kterych se zaroven zapisuje. datova struktura je transparentne chranena protectorem ktery se zavola pri pokusu o zapis/cteni do dane oblasti. to osetri tak, ze danou oblast roztrhne na dve (modified and umodified). pri pokusu o zapis na diskove zarizeni se dana oblast bufferu roztrhne a zaroven se oznami vsem threadum aby si obnovily data (toto se deje transparentne - rekneme jako korutiny v ADE!). tady jsem to napsal na par radku a za chvili a jsem si docela jisty ze bez chyb. zkuste tohle v ASM! asm neni vubec dynamicky takze byste museli delat pushf $data.buffer callf $tear_array popl %eax ; modified popl %ebx ; unmodified pushf %eax callf $pick_the_one callf <THE_DESIRED_FUNCTION> pri kazdem pristupu k polozce (cemuz se v mem jazyce dokazu vyhnout pac vim co je a co neni aliasovane tj. volatile) iterace by musely probihat nejak podezrele a jak by se resilo transparentni hlidani zapisu/cteni netusim uz vubec (overovani pred kazdym pristupem?) inteligentni dynamicky jazyk vidi spoustu veci za behu a dokaze bud znovupouzit vysledky (graph rewriting jako v haskellu apod.), nektere veci uplne vynechat apod. toho ve statickem assembleru v podstate nemuzete dosahnout navic je docela fajn ze je to obecne (nemusi to byt pouzito jen pro disky) a neskutecne paralelizovatelne (pac je to data-flow) btw: jazyk ktery pouzivam NEEXISTUJE. je kombinaci C, LISPu a ML (nebo FP, nevim co jsem to tenkrat videl ;) a to vse navic nejspis objektove (slo by to resit i jinak nez objektove?). kdyby obdobny jazyk existoval byl bych docela stastny ;) neologism (hladovy, cekajici na alkohol a sex, takze trosku mimo) P.S. pokud je to jen haluz tak sorry, mel jsem dneska docela tezky den :-) P.S. ted mne tak napadlo - existuje neco jako persistentni lambda? takovy dynamictejsi preprocesor (resp. lambda nad lambdou)neologism