Join minta
A join minta egy konkurrens (párhuzamos, elosztott) programtervezési minta, aminek lényege, hogy a szálak üzenetátadással kommunikálnak. A zárolással szemben magas szintű programozási modell, ami kommunikációs szerkezetmodellt használ, hogy elvonatkoztasson a környezet bonyolultságától, és lehetővé tegye a skálázást. Az üzenetek elfogyasztását atominak tekinti, még akkor is, ha több csatornán érkeztek az üzenetek.
Ez a minta a join-kalkuluson alapul, és mintaillesztést használ. Konkrétan ezt azzal valósítja meg, hogy lehetővé teszi függvények join definícióját, és/vagy csatornákat, amelyek konkurens hívásra illeszkednek, továbbá üzenetminták is definiálhatók. Konkurens programtervezési minták mintája (metaminta), mivel egyszerűbbé és hatékonyabbá teszi ezeknek az entitásoknak a kommunikációt és a többszálú programozási paradigma használatát.
Leírása
[szerkesztés]A join-minta egy magasabb csővezeték, szinkronizációval és mintaillesztéssel. Angolul chordnak is nevezik. Valójában a fogalom összegezhető illesztéssel és csatlakozással néhány üzenetre, amelyek különböző üzenetsorokból származnak, majd egyetlen kezelővel egyszerre kezeli őket.[1] Az első elvárt kommunikációs lépés jelezhető a when kulcsszóval, a felcsatlakozás és párosítás and kulcsszóval, és a különféle feladatok futtatása a do kulcsszóval. A join minta tipikus formája:
j.When(a1).And(a2). ... .And(an).Do(d)
A When(a1) első argumentuma lehet szinkron vagy aszinkron csatorna, de lehet csatornák tömbje is. Minden további argumentumnak aszinkron csatornának kell lennie.[2]
Pontosabban, ha egy üzenet illeszkedik minták egy összekapcsolt sorozatára, akkor elindul a kezelője egy új szálban, ha aszinkron kontextusban van, különben az üzenetnek várnia kell addig, amíg nem illeszkedik egy minta az ő valamelyik mintájára. Ha több illeszkedés van, akkor nem specifikált, hogy melyik minta választódik ki.[3] Egy eseménykezelővel szemben, ami egy időben egyszerre több alternatív esemény egyikét szolgálja ki, a join minta csatornák konjunkciójára vár, és verseng a végrehajtásért minden más megengedett mintával.[4]
A join mintát pi-kalkulusbeli csatornák halmaza definiálja, ami két műveletet definiál, a küldést és a fogadást; emiatt két join kalkulusbeli névre van szükség, egy x csatornanévre és egy x függvénynévre, az érték megszerzéséhez (egy kérés). A join definíció jelentése x() egy hívása, ami visszaadja azt az értéket, ami egy x<> csatornán érkezett. Továbbá ha több függvény fut párhuzamosan, kiváltódik a return folyamat, és együtt szinkronizálódik a többi folyamattal.[5]
J ::= //join patterns
| x<y> //message send pattern
| x(y) //function call pattern
| J | JBIS //synchronization
A kliens perspektívájából a csatorna csak deklarál egy metódust, ugyanazzal a névvel és szignatúrával. A kliens üzenetet küld vagy kérést vált ki a metódus hívásával. A folytató metódusnak várnia kell, amíg kérés vagy üzenet érkezett minden csatornán a folytatás When mondatát követően. Ha a folytatás futni kezd, akkor a csatornahívások argumentumai kikerülnek a sorból (elfogyasztódnak), és atomian átadódnak a folytatás paramétereinek. [6]
A legtöbb esetben a szinkron hívások sorrendje nem garantált a jobb teljesítmény érdekében. Az üzeneteket egy másik szál is elfogyaszthatja, így a szálnak lehet, hogy tovább kell várnia egy újabb üzenetre.[7]
Története
[szerkesztés]π-kalkulus – 1992
[szerkesztés]A π-kalkulus a folyamatkalkulusok családjába tartozik, aminek segítségével matematikai képletekkel írja le és elemzi a konkurens számítások sorozatát elnevezett csatornák bevezetésével, így a folyamatok kommunikálhatnak csatornákon keresztül, így leírhatók olyan konkurens számítások is, amelyek hálózatkonfigurációja dinamikusan, futásidőben változik.
Join kalkulus – 1993
[szerkesztés]A join minták először Fournet és Gonthier alapvető join kalkulusával jelentek meg, mint aszinkron folyamatalgebra, amit elosztott környezetben hatékony implementációhoz terveztek.[8] A join kalkulus kifejezőképessége megegyezik a π-kalkuluséval. Arra fejlesztették ki, hogy formális megalapozást adjon az elosztott programozási nyelvekhez, így elkerüli a más folyamatkalkulusokban használt kommunikációs szerkezeteket, például a randevúkat.
Elosztott join kalkulus – 1996
[szerkesztés]A join kalkulus névátadó kalkulus, és egyben magnyelv a konkurens és elosztott programozáshoz.[9] Az elosztott join kalkulus a join kalkuluson alapul, de az elosztott számításokhoz kibővítve.[10] Mobil ágenseket használ, ahol az ágensek nem egyszerűen programok, hanem futó folyamatok, a saját kommunikációs képességeikkel.
JoCaml, Funnel és Join Java – 2000
[szerkesztés]A JoCaml[11][12] és a Funnel[13][14] funkcionális programozási nyelvek, amelyek támogatják a join minták deklarálását. Közvetlenül valósítják meg a join kalkulust funkcionális programozási nyelvekben.
Egy másik kiterjesztés egy nem szabványos kiterjesztés, a Java, JoinJava, amit Itzstein és Kearney javasolt.[15]
Polyphonic C# – 2002
[szerkesztés]Cardelli, Benton és Fournet javasolta a C# bővítését join mintával 2002-ben, ez a Polyphonic C#.
Cω – 2003
[szerkesztés]A Cω a join kalkulus objektumorientált adaptációja. Tartalmazta a Polyphonic C#-ot a Cω (Comega) 2004-es kiadásában.[16]
Scala Joins – 2007
[szerkesztés]A Scala Joins egy programkönyvtár, ami lehetővé teszi a join minta alkalmazását a Scala nyelvben a kiterjeszthető mintaillesztés kontextusában, hogy a join mintát a létező aktor alapú keretrendszerbe integrálja.
JErlang – 2009
[szerkesztés]Az Erlang natívan támogatja a konkurens, valós idejű és elosztott paradigmát. A folyamatok közötti konkurenciát bonyolult volt megoldani, ezért egy új nyelvet alkottak, a JErlangot, ami a join kalkuluson alapul.
A klasszikus programozási irodalomban
[szerkesztés]Join mintával egyszerűen kódolhatók egymással kapcsolatban álló konkurens problémák, mint aktorok és aktív objektumok.[17]
class SymmetricBarrier {
public readonly Synchronous.Channel Arrive;
public SymmetricBarrier(int n) {
// create j and init channels (elided)
var pat = j.When(Arrive);
for (int i = 1; i < n; i++) pat = pat.And(Arrive);
pat.Do(() => { });
}
}
var j = Join.Create();
Synchronous.Channel[] hungry;
Asynchronous.Channel[] chopstick;
j.Init(out hungry, n); j.Init(out chopstick, n);
for (int i = 0; i < n; i++) {
var left = chopstick[i];
var right = chopstick[(i+1) % n];
j.When(hungry[i]).And(left).And(right).Do(() => {
eat(); left(); right(); // replace chopsticks
});
}
class Lock {
public readonly Synchronous.Channel Acquire;
public readonly Asynchronous.Channel Release;
public Lock() {
// create j and init channels (elided)
j.When(Acquire).And(Release).Do(() => { });
Release(); // initially free
}
}
class Buffer<T> {
public readonly Asynchronous.Channel<T> Put;
public readonly Synchronous<T>.Channel Get;
public Buffer() {
Join j = Join.Create(); // allocate a Join object
j.Init(out Put);
// bind its channels
j.Init(out Get);
j.When(Get).And(Put).Do // register chord
(t => { return t; });
}
}
class ReaderWriterLock {
private readonly Asynchronous.Channel idle;
private readonly Asynchronous.Channel<int> shared;
public readonly Synchronous.Channel AcqR, AcqW,
RelR, RelW;
public ReaderWriterLock() {
// create j and init channels (elided)
j.When(AcqR).And(idle).Do(() => shared(1));
j.When(AcqR).And(shared).Do(n => shared(n+1));
j.When(RelR).And(shared).Do(n => {
if (n == 1) idle(); else shared(n-1);
});
j.When(AcqW).And(idle).Do(() => { });
j.When(RelW).Do(() => idle());
idle(); // initially free
}
}
class Semaphore {
public readonly Synchronous.Channel Acquire;
public readonly Asynchronous.Channel Release;
public Semaphore(int n) {
// create j and init channels (elided)
j.When(Acquire).And(Release).Do(() => { });
for (; n > 0; n--) Release(); // initially n free
}
}
Alapfogalmak
[szerkesztés]- Join kalkulus: A join minta első megvalósításai ezen alapulnak.
- Üzenetátadás: A join minta párhuzamossági okok miatt üzenetátadással működik.
- Csatorna: Csatornák szinkronizálják és adnak át üzeneteket a konkurensen végrehajtott szálak között. Általában egy csatorna több join mintában is benne van, minden minta egy lehetséges folytatást definiál, ami lefuthat, ha a csatorna meghívódik.[6]
- Szinkron: A join minta használhat szinkron csatornákat, amelyek eredményt adnak vissza. A szinkron minta folytatása a szinkron hívó szálában fut.[6]
- Aszinkron: Az aszinkron csatornának nincs visszatérési értéke, de argumentumai lehetnek. Folytatása egy új szálban fut. A join minta teljesen aszinkron lehet, folytatását szubrutinban nyújtja, és When mondata csak aszinkron csatornákat tartalmaz.[6]
- Szinkron és aszinkron: A szinkron és aszinkron bufferek kombinációja egy olyan modult eredményez, ami kétféle fogyasztót támogat.[6]
- Ütemező: a join mintákat ütemezni kell, kell egy ütemező, ami ezt megoldja.[6]
- Programtervezési minták: a join minta konkurens viselkedési programtervezési minta.
- Konkurens programozás: Konkurensen hajtódik végre.
- Mintaillesztés: a join minta illeszkedő feladatokkal működik.
- Párhuzamos programozás: párhuzamosan hajtódnak végre a feladatok.
- Elosztott programozás: a join mintával felosztott feladatokat különböző ágensek hajthatják végre különböző környezetekben.
- Tranzakcionális memória: alkalmas a join minta kommunikációjának megvalósítására.
- Átfedés: a join minta számára nem probléma a különböző join minták közötti átfedés, egy csatornára több join minta is hivatkozhat.
Alkalmazások
[szerkesztés]Mobil ágenesek
[szerkesztés]A mobil ágensek autonóm programágensek társas készségekkel, kommunikációs lehetőségekkel és mozgási lehetőségekkel. A program és adatai mozoghatnak különféle gépek között futás közben.
A mobil ágensek használhatók arra, hogy összekapcsolják a konkurens és az elosztott programozást join kalkulussal. Ezért megalkották az elosztott join kalkulus fogalmát, ami helyekkel és primitívekkel bővíti a join kalkulust a mobilitás leírására. Így az ágenseknek van fogalmuk a lokációról, ami az ágens fizikai helyét jelenti. Az ágens atomi jelleggel mozoghat a különböző helyek között.[22]
Egy ágens folyamata funkcionalitásainak halmazaként definiálható, amibe beletartozik az aszinkron üzenetátadás, és a vándorlás. A mozgás könnyebb reprezentációja érdekében a helyeket fába szervezik. Ezzel a hibázás is egyszerűbben modellezhető. Ha egy helyen összeomlik a program, akkor minden alatta levő helyen is összeomlik. Egy meghatározott helyű hiba bármely futási helyről megtalálható, ez segít kijavítani a hibát.[22]
Így a join kalkulus egy elosztott nyelv magja. Operációs szemantikája egyszerűen implementálható egy elosztott rendszerben, ami a hiba lehetőségét is tartalmazza. Így a join kalkulus elsőrangú objektumokként kezeli a csatornákat és a helyeket. Egy hely ismeri más helyek nevét, ezért onnan oda lehet lépni. Ez biztos alapot teremt a statikus elemzésnek és a biztonságos mozgásnak. Teljes az elosztott helyek kifejezésében. Ha nincs hiba, akkor a végrehajtás független a helyektől. Ez az átláthatóság fontos a mobil ágensek tervezésében, és nagyon hasznos tulajdonságaik ellenőrzéséhez.[22]
2007-ben kiadták az alap join kalkulus egy proaktív ágenseket kezelő kiegészítését. Az ágensek megfigyelhetik közös környezetüket. Ehhez a közös környezethez változók adhatók az ágensekkel, például egy névszolgáltató, ami segít megtalálni más ágenseket.[23]
Szerkesztés, fordítás
[szerkesztés]A join nyelvek join kalkulusra, mint magnyelvre épülnek. Ezért a kalkulust aszinkron folyamatokkal elemzik, és a join minták modellt adnak az eredmény szinkronizálására.[9]
Ehhez két fordító szükséges:
- Join fordító: a join nyelv számára készített fordító. Ezt csak a join kalkulus számára hozták létre.
- Jocaml fordító: Az Objectif Caml egy kiterjesztésének fordítója, ami a join kalkulust használja.[24]
Ez a két fordító ugyanazon a rendszeren, egy automatán működik.
let A(n) | B() = P(n)
and A(n) | C() = Q(n)
;;
Ez egy üzenet fogyasztását reprezentálja, ami a kiegészített join modellbe érkezik. Minden állapot egy lehetőség a kód végrehajtására, és minden átmenet üzenet fogadása két állapot között. Ha minden üzenet meg van ragadva, akkor a fordító végrehajtja a join kód törzsét, a teljes join modellnek megfelelően.
Így a join kalkulusban az alapértékek nevek, mint például A, B vagy C. Így a két fordító kétféleképpen reprezentálja az eredményeket. A join fordító egy kétdimenziós vektort használ, az első a név, a második pedig a fogadott üzenetek listája. A Jocaml a neveket pointerként használja, ami a definícióra mutat. Ezek további nevek pointerét tartalmazzák állapot mezővel, és illeszkedő adatszerkezetet üzenetekkel. Az alapvető különbség az, hogy ha az őrző folyamat végrehajtódik, akkor először az üzenetben szereplő összes nevet ellenőrzi, hogy készen állnak-e a futásra, míg a második csak egy változót és hozzáférést a többihez ahhoz, hogy tudja, a modell teljes.[9]
Jelenlegi kutatások szerint a fordítási séma kétlépéses: irányításból és továbbításból áll. Az irányító tervezése és korrektsége lénygében a mintaillesztés elméletén múlik, míg egy belső irányítási lépés beszúrása a kommunikációba természetes ötlet, ami intuitívan nem változtatja meg a folyamat működését. Megfigyelték, hogy nem érdemes ennek ellenőrzése érdekében felügyelő objektumokat futás idejű szinten beiktatni, mivel ez jelentősen bonyolultabbá teszi az üzenetsorok kezelését, mivel végig kellene őket szkennelni a mintaillesztés és az üzenet elfogyasztása előtt.[25]
Implementációk és könyvtárak
[szerkesztés]A join mintákat több nyelvben is megtalálhatjuk. Egyes nyelvek implementációja is a join mintákon alapul, ilyen például a Polyphonic C# és az MC#.[26] Más nyelvek könyvtárként tartalmazzák a join mintákat. Ilyen a Scala Joins a Scala számára,[27] vagy a VB Joins könyvtára.[28] Továbbá egyes nyelvekben a join mintával fejlesztik a join mintákat, ilyen például a Scheme.[29]
JErlang | CB | Joins Library | Polyphonic C# | Parallel C# | Cω | Scala Joins | F# | Scheme | Join Java | Hume | JoCaml | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Mintaillesztés | Igen | Igen | Igen | Igen | Igen | Igen | Igen | Igen | Igen | Igen | Igen | Igen |
Ütemező a join minták között | Igen : első illesztés | Igen : első/round robin | Igen | Igen | Igen | Igen | Igen | Igen | Nem | Igen : véletlen | Igen : első/round robin | Igen : véletlen |
Generikusok | Igen | N/A | Igen | Nem | N/A | Nem | Igen | Igen | Nem | Nem | Nem | Nem |
Felüldefiniálás | Nem | Igen | N/A | N/A | N/A | Igen | Igen | Igen | Igen | Igen | Nem | Nem |
Join Java
[szerkesztés]A Join Java egy programozási nyelv, ami a Javán alapul, és amiben használhatók join minták.[30] Ezt három új nyelvi szerkezet bevezetésével éri el:
A join metódusokat két vagy több join töredékkel lehet definiálni. A join metódus ezeket próbálja meg végrehajtani. Ha a visszatérési típus szabvány Java típus, akkor a vezető töredék blokkolja a hívót, amíg a join minta nem végez, és a metódus is be nem fejeződik. Ha a visszatérési érték jel, akkor a vezető töredék azonnal visszatér. A több töredék aszinkron, nem blokkolja a hívót.
Példa:
class JoinExample {
int fragment1() & fragment2(int x) {
//will return value of x
//to caller of fragment1
return x;
}
}
Az aszinkron metódusokat jel visszatérési típusúak. Ugyanazok a jellemzői, mint a void visszatérési típus, kivéve hogy azonnal visszaér, és törzsét egy új szál hajtja végre.
Példa:
class ThreadExample {
signal thread(SomeObject x) {
//this code will execute in a new thread
}
}
Rendezési módosítók: a join töredékek különböző join mintákban szerepelnek, így lehet, hogy egy minta hívásával több join minta is illeszkedik. Az alábbi példában, ha B(), C() és D() meghívódik, akkor A() is meghívódik. Az A() töredék a minták közül háromra illeszkedik, így három metódus is meghívható. A rendezési osztálymódosító meghatározza, hogy ekkor melyik hívódjon meg; alapértelmezetten véletlenül választódik ki. A rendezési módosító prioritást állíthat fel, hogy melyik legyen előnyben.
Példa:
class ordered SimpleJoinPattern {
void A() & B() {
}
void A() & C() {
}
void A() & D() {
}
signal D() & E() {
}
}
A legközelebbi rokon nyelv a Polyphonic C#.
JErlang
[szerkesztés]Erlangban nem egyszerű megoldani a párhuzamos folyamatok szinkronizációját. Ezért hozták létre a JErlang nyelvet, ami az Erlang kiterjesztése.[31] A J betű a Join rövidítése. A bővítés elemei:
A joinok lehetővé teszik az első illesztés szemantikáját; lehetőséget ad több minta definiálására, és az üzenetek sorrendjének megőrzésére.
operation() ->
receive
{ok, sum} and {val, X} and {val, Y} ->
{sum, X + Y};
{ok, mult} and {val, X} and {val, Y} ->
{mult, X * Y};
{ok, sub} and {val, X} and {val, Y} ->
{sub, X - Y};
end
end
Az őrök további szűrést tesznek lehetővé minták nélkül. Korlátozott számú kifejezés mellékhatás nélkül.
receive
{Transaction, M} and {limit, Lower, Upper}
when (Lower <= M and M <= Upper ) ->
commit_transaction(M, Transaction)
end
Nemlineáris mintákkal az üzenet több joinra illeszthető.
receive
{get, X} and {set, X} ->
{found, 2, X}
end
...
receive
{Pin, id} and {auth, Pin} and {commit, Id} ->
perform_transaction(Pin, Id)
end
A terjesztés lehetővé teszi, hogy az üzenetek törlés helyett másolódjanak.
receive
prop({session, Id}) and {act, Action, Id} ->
perform_action(Action, Id);
{session, Id} and {logout, Id} ->
logout_user(Id)
end
...
receive
{Pin, id} and {auth, Pin} and {commit, Id} ->
perform_transaction(Pin, Id)
end
Szinkron hívások
receive
{accept, Pid1} and {asynchronous, Value}
and {accept, Pid2} ->
Pid1 ! {ok, Value},
Pid2 ! {ok, Value}
end
C++
[szerkesztés]Yigong Liu írt néhány osztályt a C++-hoz a join minta számára,[32] köztük hasznos eszközöket, mint a szinkron és aszinkron csatornák, chordok, és hasonlók. Beépült a Boost projektbe.[33]
template <typename V>
class buffer: public joint {
public:
async<V> put;
synch<V,void> get;
buffer() {
chord(get, put, &buffer::chord_body);
}
V chord_body(void_t g, V p) {
return p;
}
};
Ebben a példában egy szálbiztos buffer és egy üzenetsor látható a put és get alapműveletekkel.[34]
C#
[szerkesztés]Polyphonic C#
[szerkesztés]A Polyphonic C# a C# programozási nyelv kiterjesztése. Új konkurencia modellt vezet be szinkron és aszinkron metódusokkal és chordokkal.
public class Buffer {
public String get() & public async put(String s) {
return s;
}
}
A példa egy egyszerű buffert mutat.[35]
MC#
[szerkesztés]Az MC#[36] nyelv a Polyphonic C# adaptációja konkurens elosztott programozáshoz.
public handler Get2 long () & channel c1 ( long x )
& channel c2 ( long y )
{
return ( x + y );
}
A példa a chordot, mint szinkronizációs eszközt mutatja.
Parallel C#
[szerkesztés]A Parallel C#[37] a Polyphonic C# bővítése új fogalmakkal, mint mozgatható metódusok és magasabb rendű függvények.
using System;
class Test13 {
int Receive() & async Send( int x ) {
return x * x;
}
public static void Main( string[] args ) {
Test13 t = new Test13();
t.Send( 2 );
Console.WriteLine( t.Receive() );
}
}
A példa a joinok használatát mutatja.[38]
Cω
[szerkesztés]A Cω új nyelvi eszközöket ad a konkurrens programozáshoz a Polyphonic C# egy korábbi verziójához képest. A Joins Concurrency Library C# könyvtár és a többi .NET nyelv ebből a projektből indult ki.[39][40]
Scalable Join Patterns
[szerkesztés]A Scalable Join Patterns egy programkönyvtár, amit arra terveztek, hogy könnyen használható legyen. A Russo könyvtárral szemben,[28] nem tartalmaz globális zárat. Az atomi üzenetrendszeren és az összehasonlít-cserél rendszeren alapul. A könyvtár [41] a join minta következő kiegészítéseit tartalmazza:
- Nem használt erőforrásoknak érkezett üzenetek ellopása
- Lusta sormentés, ami allokációkor és potenciálisan a processzorközi kommunikációban az allokáció vagy a sorba tétel elkerülésével egy optimista gyors-úttal;
- Egy "WOKEN" állapot, ami biztosítja, hogy egy blokkolt szinkron hívó csak egyszer hívódik meg.
JoCaml
[szerkesztés]A JoCaml az első nyelv, amiben a join mintát implemtálták. Eleinte a többi implementációt is a JoCaml fordítóval fordították.[42] A JoCaml nyelv az OCaml kiterjesztése. A kiterjesztés támogatja a konkurenciát és a szinkronizációt, a programok elosztott végrehajtását, és a dinamikus költözést az aktívan futó programtöredékek számára[43]
type coins = Nickel | Dime
and drinks = Coffee | Tea
and buttons = BCoffee | BTea | BCancel;;
(* def defines a Join-pattern set clause
* "&" in the left side of = means join (channel synchronism)
* "&" in the right hand side means: parallel process
* synchronous_reply :== "reply" [x] "to" channel_name
* synchronous channels have function-like types (`a -> `b)
* asynchronous channels have types (`a Join.chan)
* only the last statement in a pattern rhs expression can be an asynchronous message
* 0 in an asynchronous message position means STOP ("no sent message" in CSP terminology).
*)
def put(s) = print_endline s ; 0 (* STOP *)
;; (* put: string Join.chan *)
def serve(drink) = match drink with
Coffee -> put("Cofee")
| Tea -> put("Tea")
;; (* serve: drinks Join.chan *)
def refund(v) = let s = Printf.sprintf "Refund %d" v in put(s)
;; (* refund: int Join.chan *)
let new_vending serve refund =
let vend (cost:int) (credit:int) = if credit >= cost
then (true, credit - cost)
else (false, credit)
in
def coin(Nickel) & value(v) = value(v+5) & reply () to coin
or coin(Dime) & value(v) = value(v+10) & reply () to coin
or button(BCoffee) & value(v) =
let should_serve, remainder = vend 10 v in
(if should_serve then serve(Coffee) else 0 (* STOP *))
& value(remainder) & reply () to button
or button(BTea) & value(v) =
let should_serve, remainder = vend 5 v in
(if should_serve then serve(Tea) else 0 (* STOP *))
& value(remainder) & reply () to button
or button(BCancel) & value(v) = refund( v) & value(0) & reply () to button
in spawn value(0) ;
coin, button (* coin, button: int -> unit *)
;; (* new_vending: drink Join.chan -> int Join.chan -> (int->unit)*(int->unit) *)
let ccoin, cbutton = new_vending serve refund in
ccoin(Nickel); ccoin(Nickel); ccoin(Dime);
Unix.sleep(1); cbutton(BCoffee);
Unix.sleep(1); cbutton(BTea);
Unix.sleep(1); cbutton(BCancel);
Unix.sleep(1) (* let the last message show up *)
;;
gives
Coffee Tea Refund 5
Hume
[szerkesztés]A Hume[44] egy szigorú, erősen típusozott funkcionális nyelv korlátozott erőforrásokkal rendelkező platformok számára, aminek konkurenciája aszinkron üzenetátadáson alapul, tartalmaz adatfolyam programozást. Szintaxisa hasonlít a Haskellhez.
A Hume nem tartalmaz szinkron üzenetátadást.
A join minta készletek közös csatornákat tartalmaznak, mint box (doboz), amely egy in tuple összes csatornáján hallgat, és minden lehetséges kimenetet egy out tupléban definiál.
Egy join mintának meg kell felelnie a box input tuple típusnak, amit '*' jelöl a nem igényelt csatornákra, kifejezéstípusa pedig megfelel az output tuple típusnak, amit '*' jelöl a nem táplált kimenetekre.
Egy wire mondat meghatározza a következőket:
- tuple a megfelelő input eredetekhez vagy forrásokhoz és opcionálisan kezdőértékek
- tuple az output célokhoz, amelyek csatornák vagy sinkek (stdout, ..).
Egy box specifikálhatnak kivételkezelőket az output tuplénak megfelelő kifejezésekkel.
data Coins = Nickel | Dime;
data Drinks = Coffee | Tea;
data Buttons = BCoffee | BTea | BCancel;
type Int = int 32 ;
type String = string ;
show u = u as string ;
box coffee
in ( coin :: Coins, button :: Buttons, value :: Int ) -- input channels
out ( drink_outp :: String, value’ :: Int, refund_outp :: String) -- named outputs
match
-- * wildcards for unfilled outputs, and unconsumed inputs
( Nickel, *, v) -> ( *, v + 5, *)
| ( Dime, *, v) -> ( *, v + 10, *)
| ( *, BCoffee, v) -> vend Coffee 10 v
| ( *, BTea, v) -> vend Tea 5 v
| ( *, BCancel, v) -> let refund u = "Refund " ++ show u ++ "\n"
in ( *, 0, refund v)
;
vend drink cost credit = if credit >= cost
then ( serve drink, credit - cost, *)
else ( *, credit, *);
serve drink = case drink of
Coffee -> "Cofee\n"
Tea -> "Tea\n"
;
box control
in (c :: char)
out (coin :: Coins, button:: Buttons)
match
'n' -> (Nickel, *)
| 'd' -> (Dime, *)
| 'c' -> (*, BCoffee)
| 't' -> (*, BTea)
| 'x' -> (*, BCancel)
| _ -> (*, *)
;
stream console_outp to "std_out" ;
stream console_inp from "std_in" ;
-- dataflow wiring
wire cofee
-- inputs (channel origins)
(control.coin, control.button, coffee.value’ initially 0)
-- outputs destinations
(console_outp, coffee.value, console_outp)
;
wire control
(console_inp)
(coffee.coin, coffee.button)
;
Visual Basic
[szerkesztés]Concurrent Basic – CB
[szerkesztés]A Concurrent Basic a Visual Basic 9.0 kiterjesztése aszinkron konkurenciaszerkezetekkel a join minták kifejezésére. A CB a korábbi Polyphonic C#, Cω és Joins Library tapasztalatain alapulva adoptál egy egyszerű eseményszerű szintaxist, ami ismerős a VB programozók számára, és lehetővé teszi generikus konkurencia absztrakciók definiálását, továbbá természetesebb támogatást nyújt az öröklődésnek, megengedve az alosztálynak a minták bővítését. Egy CB osztály deklarálhat metódust, ami meghívódik ha kommunikációs esemény történt csatornák egy join mintát meghatározó halmazán.[28]
Module Buffer
Public Asynchronous Put(ByVal s As String)
Public Synchronous Take() As String
Private Function CaseTakeAndPut(ByVal s As String) As String _
When Take, Put
Return s
End Function
End Module
A példa bemutatja a Concurrent Basicbe bevezetett új kulcsszavakat: Asynchronous, Synchronous és When.[45]
Joins könyvtár (C# és VB)
[szerkesztés]Ez a könyvtár a join minta magas szintű absztrakciója, ami objektumokat és generikusokat használ. A csatornák speciális delegált értékek valamely közös Join objektum (metódusok helyett).[46]
class Buffer {
public readonly Asynchronous.Channel<string> Put;
public readonly Synchronous<string>.Channel Get;
public Buffer() {
Join join = Join.Create();
join.Initialize(out Put);
join.Initialize(out Get);
join.When(Get).And(Put).Do(delegate(string s) {
return s;
});
}
}
A példa azt mutatja, hogyan lehet egy Join objektum metódusait használni.[47]
Scala
[szerkesztés]A Scala Joins[48] egy Scala könyvtár a join minta használatához. A mintaillesztés egy eszköz join modellek készítéséhez. Példák itt: Join definitions in Scala
A nyelv mintaillesztési lehetőségei általánosíthatók, hogy lehetővé tegye a mintaillesztésben használt objektumok független reprezentációját. Most a könyvtárakban használható egy új típusú absztrakció. A join mintának az az előnye, hogy megengedi a különböző szálak szinkronizációjának deklaratív specifikációját. A join minta megfeleltethető egy véges állapotgépnek, ami specifikálja az objektum érvényes állapotait.
class ReaderWriterLock extends Joins {
private val Sharing = new AsyncEvent[Int]
val Exclusive, ReleaseExclusive = new NullarySyncEvent
val Shared, ReleaseShared = new NullarySyncEvent
join {
case Exclusive() & Sharing(0) => Exclusive reply
case ReleaseExclusive() => { Sharing(0); ReleaseExclusive reply }
case Shared() & Sharing(n) => { Sharing(n+1); Shared reply }
case ReleaseShared() & Sharing(1) => { Sharing(0); ReleaseShared reply }
case ReleaseShared() & Sharing(n) => { Sharing(n-1); ReleaseShared reply }
}
Sharing(0) }
Egy osztályban eseményeket definiálunk adattagként. Így lehet a join szerkezetet, hogy lehetővé tegye a mintaillesztést eset deklarációkkal. A lista => jellel kapcsolja össze a deklaráció részeit. A bal oldal join minta egy modellje, ami események szinkron vagy aszinkron kombinációját jelzi, a jobb oldal pedig végrehajtódik, ha a join minta teljesül.
Scalaban lehet az actor könyvtárat is használni.[49] a join mintával.Például egy nem korlátos buffer:[27]
val Put = new Join1[Int]
val Get = new Join
class Buffer extends JoinActor {
def act() {
receive { case Get() & Put(x) => Get reply x }
} }
A könyvtár támogatja az aktor alapú konkurenciát, és a join minta ennek kiterjesztése, így lehetséges kombinálni a join mintákat és az eseményvezérelt konkurenciamodellt, amit az aktorok nyújtanak. Ahogy a példában látható, ez ugyanaz, mint aktorokkal használni a join mintákat, csak eseteket kell deklarálni a fogadó metódusban, hogy megtudjuk, hogy a modell teljes.
Ugyanezek az eszközök elérhetők az F# számára is.
A Scala Join[50] és a Chymyst[51] a join minta újabb megvalósításai, amelyek Dr. Philipp Haller Scala Joinsán[52] alapulnak.
Haskell
[szerkesztés]A Join Language[53] a join minta implementációja a Haskell számára.
Scheme
[szerkesztés]A join minta lehetővé tesz egy új programozási stílust speciálisan a többmagos architektúrák számára, ami sok programozási helyzetben elérhető, és magas szintű absztrakciót nyújt. Ez a Guardokon (őrök) és Propagationön (továbbításon) alapul. A következőkben ennek egy megvalósítását ismertetjük a Scheme nyelvben.[29]
Az őrök ahhoz fontosak, hogy csak az illeszkedő kulcsú adatok frissüljenek vagy lehessenek találatok. PA továbbítás töröl egy itemet, elolvassa a tartalmát és visszahelyez egy itemet a készletbe. Olvasás alatt az item megtalálható a készletben. Az őrök osztott változókkal fejezhetők ki. Az újdonság az, hogy a join minta tartalmazhatja a most továbbított és egyesített részeket. Így a Scheme-ben a továbbítás előtti vagy alatti részeket és az eltávolítás előtti és utáni részeket. A Goal-Based (cél alapú) használata ia munkát sok feladatra osztja és joinolja az összes végeredményt az összes join mintával. Egy "MiniJoin" nevű rendszert arra alkottak, hogy a köztes eredményt felhasználja más feladatok megoldásához, ha ez lehetséges. Ha ez nem lehetséges, akkor megvárja a többi feladatot, hogy felhasználhassa a végeredményüket.
Így a konkurens join minta alkalmazása párhuzamosan hajtódik végre egy többmagos rendszeren, ami viszont nem garantálja, hogy nem lesznek ütközések. Ezt a szoftvertranzakciós memória (STM) intézi egy erősen hangolt konkurens adatszerkezetben, ami atomi összehasonlításon és cserén (CAS) alapul. Ez megengedi, hogy sok konkurens művelet fusson párhuzamosan egy többmagos architektúrán. Továbbá atomi végrehajtást használ a CAS és STM közötti hamis konfliktus elkerülésére.[29]
Hasonló minták
[szerkesztés]A join minta nem az egyetlen, ami alkalmas egyszerre több szál futtatására, de az egyetlen, ami lehetővé teszi a kommunikációt az erőforrások, a szinkronizáció és a különböző folyamatok joinja között.
- Szekvencia minta: az egyik feladatnak meg kell várnia, amíg az előző végez (klasszikus implementáció).
- Split minta: párhuzamosan végrehajt néhány feladatot.
Jegyzetek
[szerkesztés]- ↑ Taral Dragon: Join Calculus, 2009. október 25. (Hozzáférés: 2012)
- ↑ (2008. október 23.) „Join Patterns for Visual Basic”, Nashville, Tennessee, USA, 10. o.
- ↑ Parallel C#. (Hozzáférés: 2012)
- ↑ „Join Patterns for Visual Basic”, 2. o.
- ↑ (2002) „The Join Calculus: a Language for Distributed Mobile Programming”, Caminha, 8. o.[halott link]
- ↑ a b c d e f Join Patterns for Visual Basic Claudio V. Russo.
- ↑ (2008. október 23.) „Join Patterns for Visual Basic”, Nashville, Tennessee, USA, 5. o.
- ↑ (2008. október 23.) „Join Patterns for Visual Basic”, Nashville, Tennessee, USA, 18. o.
- ↑ a b c (2007. szeptember 25.) „Compiling Join-Patterns”, Le Chesnay France.
- ↑ (1996) „A Calculus of Mobile Agents”, Le Chesnay, 406–421. o, Kiadó: Concurrency Theory.[halott link]
- ↑ (2000. szeptember 1.) „JoCaml: a language for concurrent distributed and mobile programming.”. In Advanced Functional Programming, 4th International SchoolOxford, August 2002 2638.
- ↑ (1999) „JoCaml: Mobile agents for Objective-Caml”. In First International Symposium on AgentSystems and Applications. (ASA'99)/Third International Symposium onMobile Agents (MA'99).
- ↑ (2000. szeptember 1.) „An overview of functional nets.”. Summer School, Caminha, Portugal, September 2000 2395.
- ↑ (2000) „Functional nets.”. In Proceedings of the European Symposium on Programming. Lecture Notes in Computer Science 1782.
- ↑ (2001) „Join Java: An alternative concurrency semantics for Java”. Echnical Report ACRC-01-001, University of South Australia.
- ↑ (2002. június 1.) „Modern concurrency abstractions for C#.”. In Proceedings of the 16th European Conference on Object-Oriented Programming (ECOOP 2002), number 2374 in LNCS.
- ↑ Singh, Satnam (2007. január 6.). „Higher Order Combinators for Join Patterns using STM”, 1. o.
- ↑ a b (2011. október 27.) „Scalable Join Patterns”, Portland, Oregon, USA, 4. o.
- ↑ (2011. október 27.) „Scalable Join Patterns”, Portland, Oregon, USA, 1. o.
- ↑ a b (2011. október 27.) „Scalable Join Patterns”, Portland, Oregon, USA, 3. o.
- ↑ (2011. október 27.) „Scalable Join Patterns”, Portland, Oregon, USA, 2. o.
- ↑ a b c (1996) „A Calculus of Mobile Agents”, Le Chesnay, Kiadó: Concurrency Theory.[halott link]
- ↑ (2007) „Multi-Agent Systems and Applications V”. Lecture Notes in Computer Science 4696, 298–300. o. DOI:10.1007/978-3-540-75254-7_30.
- ↑ http://pauillac.inria.fr/jocaml/ Archiválva 2005. október 1-i dátummal a Wayback Machine-ben Jocaml Compiler
- ↑ (2004. április 5.) „Compiling Pattern Matching in Join-Patterns”, 417–431. o, Kiadó: INRIA.[halott link]
- ↑ http://www.mcsharp.net/
- ↑ a b (2008) „Implementing Joins using Extensible Pattern Matching”, Lausanne, 1–15. o, Kiadó: Coordination Models and Languages.[halott link]
- ↑ a b c (2008. október 23.) „Join Patterns for Visual Basic”, Nashville, Tennessee, USA, 53–72. o.
- ↑ a b c „Parallel Join Patterns with Guards and Propagation”, Denmark.
- ↑ (2002) „Hardware Join Java: A High Level Language For Reconfigurable Hardware Development”, Hong Kong. [2013. február 19-i dátummal az eredetiből archiválva]. (Hozzáférés: 2017. július 6.)
- ↑ (2009) „JErlang: Erlang with Joins”, London. [2017. október 10-i dátummal az eredetiből archiválva]. (Hozzáférés: 2017. július 7.)
- ↑ osztályok a join mintákhoz
- ↑ Boost c++.
- ↑ Join - Asynchronous Message Coordination and Concurrency Library, 2007. december 8. (Hozzáférés: 2012)
- ↑ Introduction to Polyphonic C#. (Hozzáférés: 2012)
- ↑ MC#
- ↑ Parallel C#
- ↑ Parallel C#. [2013. november 26-i dátummal az eredetiből archiválva]. (Hozzáférés: 2012)
- ↑ The Joins Concurrency Library. (Hozzáférés: 2012)
- ↑ Comega. (Hozzáférés: 2012)
- ↑ (2011. október 27.) „Scalable Join Patterns”, Portland, Oregon, USA.
- ↑ JoCaml nyelv
- ↑ JoCaml: a Language for Concurrent Distributed and Mobile Programming, Advanced Functional Programming, Lecture Notes in Computer Science. Springer-Verlag, 129-158. o. (2003)
- ↑ Hammond/Michaelson/Sun - Programming reactive systems in Hume
- ↑ Concurrent Basic. [2015. április 25-i dátummal az eredetiből archiválva]. (Hozzáférés: 2012)
- ↑ (2007) „The Joins Concurrency Library”, Cambridge, 260–274. o, Kiadó: Practical Aspects of Declarative Languages.[halott link]
- ↑ The Joins Concurrency Library. (Hozzáférés: 2012)
- ↑ Scala Joins
- ↑ (2007. június 1.) „Actors that unify threads and events”, Kiadó: In Proc. COORDINATION, LNCS.
- ↑ Scala Join
- ↑ Chymyst
- ↑ Scala Joins. [2016. március 3-i dátummal az eredetiből archiválva]. (Hozzáférés: 2017. július 7.)
- ↑ Join Language
Források
[szerkesztés]- The Join-Calculus language. Institut National de Recherche en Informatique et Automatique, 2006. augusztus 15. (Hozzáférés: 2012. október 9.)
- JoinCalculus. Cunningham & Cunningham, Inc., 2009. október 25. (Hozzáférés: 2012. október 9.)
- (1996) „A Calculus of Mobile Agents”, Le Chesnay, 406–421. o, Kiadó: Concurrency Theory.[halott link]
- (2007) „Agent Environment and Knowledge in Distributed Join Calculus”. Lecture Notes in Computer Science, 298–300. o. DOI:10.1007/978-3-540-75254-7_30.
- (2007) „The Joins Concurrency Library”, Cambridge, 260–274. o, Kiadó: Practical Aspects of Declarative Languages.[halott link]
- (2007. szeptember 25.) „Compiling Join-Patterns”, Le Chesnay France.
- (2008) „Implementing Joins using Extensible Pattern Matching”, Lausanne, 1–15. o, Kiadó: Coordination Models and Languages.[halott link]
- „Parallel Join Patterns with Guards and Propagation”, Denmark.
- (2002) „The Join Calculus: a Language for Distributed Mobile Programming”, Caminha, 1–66. o.[halott link]
- (2004. április 5.) „Compiling Pattern Matching in Join-Patterns”, 417–431. o, Kiadó: INRIA.[halott link]
- Singh, Satnam (2007. január 6.). „Higher Order Combinators for Join Patterns using STM”.
- MONSIEUR, Geert (2010), Pattern-based Coordination in Process-based Service Compositions, Leuven Belgium: Katholiek Universiteit Leuven, <https://lirias.kuleuven.be/handle/123456789/284037>
- (2008. október 23.) „Join Patterns for Visual Basic”, Nashville, Tennessee, USA, 53–72. o.
- (2011. október 27.) „Scalable Join Patterns”, Portland, Oregon, USA.
- Guzev, Vadim B. (2008. április 1.). „Parallel C#: The Usage of Chords and Higher-Order Functions in the Design of Parallel Programming Languages”, Moscow, Russia.
Fordítás
[szerkesztés]Ez a szócikk részben vagy egészben a Join-pattern című angol Wikipédia-szócikk fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel. Ez a jelzés csupán a megfogalmazás eredetét és a szerzői jogokat jelzi, nem szolgál a cikkben szereplő információk forrásmegjelöléseként.