Colorgraph

C# struktura za upravljanje procesima

Preuzmi

zip sa izvornim kodom sa GitHuba · C#, 2013
Izvorni kod na GitHubu

C# struktura za upravljanje procesima. Napisana 2013. godine; prevedena sa originalne ruske stranice.

Kako početi

  1. Razmisli koji tipovi podataka ulaze u tvoje procese i izlaze iz njih. Za svaki tip napravi posebnu boju nasleđenu od Color. Ili uzmi ColorTemplate<T> i preskoči ceremoniju.
  2. Napiši svaki proces u svom grafu. Najbolje ih nasledi od SimpleGraphNode<T>, uz prepisan Stop i, po potrebi, Undo. Ako proces mora da radi nešto neobično sa ulaznim bojama, nasledi GraphNode i prepiši Work u celosti.
  3. Napravi prve čvorove grafa i daj im početnu boju. OutPoint i SerialOutPoint primaju početnu boju u konstruktoru.
  4. Sastavi graf od tih prvih čvorova pomoću ConnectTo.
  5. Napravi graf sa new, prosleđujući konstruktoru čvorove čije te krajnje vrednosti zanimaju. Ako prosledeš čvor koji nije prvi, svaki čvor pre njega dobiće Undo signal.
  6. Definiši OnFinish obrađivače na grafu, ili na bilo kom njegovom čvoru, da obradiš rezultate.
  7. Pokreni sa Start ili StartAsync.

Detaljnije

Pojmovi

Graf boja je usmereni aciklični graf čiji su čvorovi procesi. Svaki čvor i svaka grana mogu da se oboje, i svakom čvoru i grani može da se pošalje signal.

Boja su podaci određenog tipa koji putuju između čvorova. Signal su podaci određenog tipa koji putuju granama u suprotnom smeru. Grana je objekat koji spaja dva čvora i ima pozitivnu dužinu.

Aksiome

Graf poštuje nekoliko pravila:

  1. Svaki objekat (čvor ili grana) može da se oboji.
  2. Već obojen objekat sme da se preboji samo u crno.
  3. Čvor sam odlučuje koju boju uzima i pod kojim uslovom. Jedine garancije: ako su sve ulazne grane obojene, obojen je i čvor; ako su sve ulazne grane crne, čvor je crn.
  4. Svakom objektu može da se pošalje signal u suprotnom smeru grafa (od kraja ka početku).
  5. Signali su dve vrste: serijski i broadcast.
  6. Objekat prima samo jedan serijski signal, ostale ignoriše.
  7. Čvor sam odlučuje kako i kada obrađuje serijski signal. Jedina garancija: ako su sve izlazne grane signalizirale, signalizira i čvor.
  8. Broadcast signal čvor odmah prosleđuje dalje uz stablo. Čvor koji je već video broadcast sa datim brojem posle ga ignoriše.

Čvorovi

Iz ovih aksioma sledi nekoliko vrsta čvorova koji se različito odnose prema boji i signalima. Kad se neke vrste povežu međusobno, suvišne grane se odbacuju da se uštede resursi.

Ulazna tačka (InPoint)

Ulazna tačka: kako se boji
Ulazna tačka (InPoint): kako se boji.

Ulazna tačka je čvor sa više ulaznih grana i tačno jednom izlaznom. Da bi se uštedeli resursi i logika ostala jednostavna, izlazna grana se odbacuje i ulazna tačka se kači direktno na sledeći čvor (njen Parent). Čim je bilo koja ulazna grana obojena, ulazna tačka uzima njenu boju. Svaki signal koji ulazna tačka primi odmah šalje u sve ulazne grane.

Izlazna tačka (OutPoint)

Izlazna tačka: kako se boji
Izlazna tačka (OutPoint): kako se boji.

Izlazna tačka ima jednu ulaznu granu i više izlaznih. Čim se oboji, boje se sve izlazne grane. Na serijski signal sa jedne izlazne grane čeka dok sve ostale ne signaliziraju, pa šalje AllPosibilitiesFailedException sa greškama svake grane redom kako su stigle, tako da je prva greška na čelu liste.

Izlazne tačke šalju jednu boju u više pravaca odjednom. Zakači jednu na čvor „sačuvaj kao JPEG“ i na čvor za bekap, i jedan niz fotografija se čuva kao JPEG i bekapuje paralelno, u odvojenim nitima. Ako više čvorova treba istu boju, koristi jednu izlaznu tačku, a ne više njih sa istim podacima. Samo imaj na umu da tačka čuva ceo lanac grešaka sa svih svojih grana, pa ako treba da pratiš greške u jednoj konkretnoj grani, zakači je samo na tu granu, jel da.

Serijska izlazna tačka (SerialOutPoint)

Serijska izlazna tačka: kako se boji
Serijska izlazna tačka (SerialOutPoint): kako se boji.

Serijska izlazna tačka boji izlazne grane jednu po jednu i čeka da svaka završi. Prva se boji najkraća grana i postaje tekuća; čvor čeka njen signal. Na signal o grešci najkraća neobojena grana postaje tekuća, boji se, i čekanje kreće ispočetka. Signali sa bilo koje grane osim tekuće se ignorišu.

Čemu služe serijske izlazne tačke? Uglavnom lancima u kojima unapred ne znaš koji od više sličnih čvorova može da obavi posao. Recimo, treba da konvertuješ video sa zadatim parametrima, imaš više konvertera, svaki podržava druge formate, i ne možeš unapred da znaš koji će uspeti. Pošalji parametre konverzije i ime fajla serijskoj izlaznoj tački, na svaki izlaz zakači konverter, a izlaze svih konvertera spoji u jednu ulaznu tačku. Serijska tačka pokreće prvi konverter; ako on padne, drugi, i tako dalje, dok neki ne konvertuje fajl i ne preda ga zajedničkoj ulaznoj tački. Neiskorišćeni konverteri se gase bojenjem u crno. Ako nešto pukne dalje niz lanac, serijska tačka vraća i tu grešku.

Radni čvor (WorkNode)

Radni čvor: kako se boji
Radni čvor (GraphNode): kako se boji.

Na radni čvor je zakačeno više ulaznih tačaka i jedna izlazna. On pretvara ulazne boje algoritmom koji piše programer. Čeka dok se svaka ulazna tačka bez izuzetka ne oboji, pretvara njihove boje i boji sebe rezultatom. Ako rezultat ne može da se dobije, čvor šalje signal o grešci i boji sebe u crno. Svaki primljeni signal odmah prosleđuje dalje uz stablo. Pretvaranje, zaustavljanje i poništavanje (Work, Stop, Undo) garantovano se izvršavaju u posebnoj niti.

Kako se izvršava

Da bi se graf pokrenuo sa Start ili StartAsync, navodiš njegove ključne čvorove. Kad svi oni prime serijski signal, izvršavanje je gotovo. Putanje se prate samo za te čvorove i samo oni daju rezultat grafa (GraphResult).

Pre pokretanja, svi mogući poslednji čvorovi i viseće grane skupljaju se u listu Last. Za svaki od njih, svaki početni čvor i grana koji mogu da dovedu do njega idu u listu First, a boje svih prvih objekata čuvaju se posebno. Graf je spreman. Ima četiri glavna metoda: Stop, Clear, Start, Undo.

Kad svi ključni čvorovi signaliziraju, pokreće se Finish i nalazi najduže putanje kojima je boja prošla od ključnih objekata. Zašto najduže? U teoriji je to najduži lanac pretvaranja bez greške. Nazad na primer sa videom: svaku video traku treba izvući u poseban fajl, konvertovati i spojiti sa ostalim trakama. Ako usput ništa nije puklo, izvršavanje se završava lancem „traka → fajl nekonvertovane trake → fajl konvertovane trake → spojeni fajl sa više traka“, i taj lanac možeš da obradiš kako hoćeš, na primer da obrišeš sve privremene fajlove. Ako je neka faza pukla, dobijaš deo lanca do mesta greške i možeš, recimo, da zadržiš privremene fajlove i kažeš korisniku da spajanje nije uspelo, ali da je izvlačenje trake prošlo. Ako graf ima izlazne tačke, dužine njihovih grana podešavaju dužinu konačne putanje.

Kad su najduže putanje nađene, svaki objekat van njih dobija Undo signal, pa čvor koji je napravio privremeni fajl briše ga. Kad je izvršavanje gotovo i putanje nađene, okida se OnFinish.

O bojama

Boja je klasa nasleđena od Color. To bi, naravno, bilo previše jednostavno, jer boje mogu da se mešaju. Color je element povezane liste, cela lista opisuje mešavinu boja, a bilo koji element potpuno određuje listu. Tako da kad objekat grafa primi boju, zapravo prima mešavinu, koju možeš da raspakuješ sa Color.Demix(). Mešavina se pravi statičkim Color.Mix().

Zašto zavaravati programera običnim Color kad bi ColorMix sve rekao sam? Zato što mešavine postoje uglavnom za debagovanje: možeš da umešaš debag informacije u pravi rezultat funkcije i izvučeš ih nazad sa Demix, dok sledeći čvor vidi običnu boju bez dodataka. Ako boja prođe filter po tipu, čvor je prihvata kao „dobru“ i radi s njom ne primećujući primese. Svaka boja može da se tretira i kao jedna nijansa i kao mešavina, zavisno od toga šta rade funkcije čvora.

Dobra praksa: koristi mešavine samo za debagovanje i napravi posebnu boju za svaki tip podataka koji funkcije tvog čvora koriste. Ako čvor prima string, logičku vrednost i niz brojeva neograničene dužine, daj mu dva nevidljiva ulaza za string i logičku vrednost, izložena kao svojstva, a čvor proglasi za onaj koji prima brojeve. Onda svi brojevi stižu kao „dobre“ boje, dok string i logička vrednost sede na nevidljivim ulazima.