A Pool egy objektum-orientált, párhuzamos programozásra alkalmas nyelv, amely nem megosztott memóriával rendelkező párhuzamos gépekre lett fejlesztve. Egy ilyen gép volt a 100-node Doom (Decentralized Object-Oriented Machine) amelyen már futtatni is lehetett a Pool-ban írt programokat. A POOL nyelvcsalád része a POOL, POOL2, POOL-I, POOL-T (valamint nem párhuzamás környezetre az SPOOL).
Az "üzenetküldés" terminológiája ellenére a legtöbb OOP nyelv szekvenciális, azaz az alábbi 3 megszorításnak eleget tesz:
Először olyan szempontból vizsgáljuk meg a fenti megközelítéseket, hogy
mennyire segítik megoldani a párhuzamosság problémáját. A párhuzamos
programozás lelke a processzek egyenlőtlen végrehajtásából adódó
nemdeterminisztikusság kezelése: ezt a minimumra kellene szorítani, de egy
bizonyos mennyiségnek maradnia kell, hogy hatékonyan kihasználja a
párhuzamosságot. Ez a nemdeterminisztikusság nagyon gyorsan növekszik a
processzek és azon belül az atomi utasítások számának növelésével.
Az első megközelítés hátrányai nyilvánvalóak: a processz végrehajtásának
minden pillanatában várhat interakciót (azaz inkább megszakítást). Külön
mechanizmusok szükségesek a nemdeterminisztikusság csökkentésére (pl.
szemaforok). Ezek fegyelmezett használatot igényelnek, melyet nem
kényszerít ki a nyelv. Ezek miatt ez a megközelítés nem alkalmas
nagyméretű párhuzamos programokhoz.
A párhuzamos programozás osztott változókkal és
üzenetküldéssel megvalósított formája. Az osztott változókkal dolgozás
nehézségei rögtön kiderülnek, mihelyst összevetjük az üzenetküldéssel. Ez
az osztott változós programok ellenőrzésének formalizációjakor rögtön
kiderül. Az ilyen programok formális ellenőrzésének klasszikus rendszerei
szerint invariáns állítást kell adnunk minden processz minden más
processzel való kapcsolata előtt és után. Például n processz és m
kapcsolattal és m+1 állítással n*(m+1)*m*(n-1) ellenőrzést igényel. Az n
csökkentése a párhuzamosságot csökkenti, míg m csökkentése megoldható
az atomi eljárások méretének növelésével. Pontosan ez történik üzenetküldés
során. Sőt, mivel a partnert gyakran jelzik explicit, ez az ellenőrzést
leszorítja egypár résztvevő kommunikációs állításra, ami jóval kevesebb
ellenőrzést igényel.
Természetesen az osztott változók és az üzenetküldés közti választást
befolyásolja a gép architektúrája. Osztott memóriával rendelkező
rendszerekben és szekvenciális rendszerekben az osztott változók
implementálása triviális. Másrészről az osztott memória nélküli,
kommunikációs hálózattal összekapcsolt processzorok esetén az
üzenetküldés rendszere illeszkedik az architektúrához. Ilyen gépen bár lehet,
de nagyon nehéz és nem hatékony osztott változókat implementálni. Tehát,
ha nem ismert az architektúra, akkor jobb az üzenetküldést választani.
Az eddigiek mutatják, hogy az objektumok és a párhuzamosítás
összeegyeztetésekor a másik két megközelítés célszerűbb. (tehát az
aszinkron kommunikáció vagy a törzsek) Itt az objektum és a processz
fogalma eggyé válik, és ezek a szavak szinonimák lesznek. A processzek
csak jóldefiniált helyeken kapcsolódhatnak, sőt a kapcsolat módja is csak a
paraméterek és az eredmények küldésére korlátozódik. Az objektum változói
más objektumoktól védve vannak. Ha adatokat kell több processz közt
megosztani, akkor egy külön objektumba rakjuk őket, s így elérésük is
jóldefiniált lesz a metódusokon keresztül. Az objektumon belül minden
szekvenciálisan történik, azaz a szekvenciális belső elkülönül a párhuzamos
külsőtől. Ha megengednénk több párhuzamos processzt is egy objektumon
belül, az csak elrontaná ezt a kedvező helyzetet.
Az aszinkron kommunikáció és a törzsek közti döntés már nem olyan
nyilvánvaló, mint az előző esetben. A szinkronizáció hiánya nem csak a
rendszer rugalmasságát növeli meg, kihasználva az erőforrásait, de felvet
néhány problémát is: Sokkal többféle futása lehel, mint szinkron
kommunikáció esetében, és a programozónak kell biztosítani, hogy mind
helyes eredményt ad. A másik probléma a már elküldött, de még meg nem
érkezett üzenetek pufferelése. Elvben nem használhatunk rögzített
pufferméretet blokkolva a küldőt, ha több üzenetet próbálna küldeni, mint a
pufferméret, mert ez holtpontot idézhet elő a szemantikailag helyes
programban is. Például ha a küldő n darab 'a' üzenetet küld aztán egy 'b'-t
míg a fogadó egy 'b'-t vár először, akkor holtpont alakul ki, ha n nagyobb,
mint a pufferméret.
Egy másik probléma, hogy hogyan garantáljuk, hogy ugyanazon küldő és
fogadó közt az üzenetek érkezési sorrendje megegyezzen a küldési
sorrendjükkel. Ez biztosítható, ha protokollokkal vagy fix rutinokkal látjuk
el a hálózat minden kapcsolódó csúcsát, és ügyelünk, hogy a sorrend az
átvitel minden pontjában megmaradjon. Ez azonban lassítja a programot.
Megjegyezzük, hogy könnyű aszinkron kommunikációt implementálni olyan
nyelven ami csak szinkron kommunikációt és törzset tartalmaz: minden
aszinkron üzenetnek egy puffer objektumot kell létrehozni. A POOL-ban
szinkron kommunikációt és törzset választottunk a párhuzamosság
kifejezéseként. Ha a programozó nem ír törzset, egy alapértelmezett törzset
használ a rendszer, ami folyamatosan válaszol a beérkezett utasításokra. Egy
metódus még a befejezése előtt visszaadhat eredményt a küldőnek.
Az üzenetek átvételére az answer utasítás szolgál. Az utasítás egy
metódusnév listát is tartalmaz. Azaz pontosan egy üzenet válaszolódik meg,
az első olyan, ami a listában szereplő metódusnevekre hivatkozik. A POOL2
feltételes answer utasítást is tartalmaz, ami specifikálja, hogy egy üzenet
csak akkor válaszolódjon meg, ha egy feltételnek megfelel. Ha nincs ilyen
üzenet, a feltételes answer utasítás azonmód terminál. Ez az Ada-szerű select
utasítás általánosítása.
A POOL2-ben az aszinkron kommunikáció is támogatott. Ez úgy tekinthető,
mintha egy puffer objektum keletkezne minden üzenethez, azaz az üzenetek
sorrendje nem biztosított.
Összehasonlítva a POOL-t a hagyományos párhuzamos nyelvekkel,
egyszerűen besorolhatók a következők szerint: