OpenJDK Project Loom
1. Áttekintés
Ebben a cikkben gyorsan áttekintjük a Project Loom-ot. Összefoglalva, a Project Loom elsődleges célja egy nagy áteresztőképességű, könnyű egyidejűségi modell támogatása a Java-ban.
2. Projekt Loom
A Project Loom az OpenJDK közösség kísérlete egy könnyű, egyidejűség-konstrukció bevezetésére a Java-ban. A Loom eddigi prototípusai változást vezettek be a JVM-ben, valamint a Java könyvtárban.
Bár a Loom számára még nincs tervezett kiadás, a legújabb prototípusokat a Project Loom wikijében érhetjük el.
Mielőtt megvitatnánk a Loom különféle fogalmait, beszéljük meg a Java egyidejűségének jelenlegi modelljét.
3. Java egyidejűségi modell
Jelenleg, cérna a párhuzamosság alapvető elvonását jelenti a Java-ban. Ez az absztrakció a többi egyidejű API-val együtt megkönnyíti az egyidejű alkalmazások írását.
Mivel azonban a Java az operációs rendszer kernelszálait használja a megvalósításhoz, nem felel meg a párhuzamosság mai követelményének. Különösen két fő probléma van:
- Szálak nem egyezhet a tartomány párhuzamossági egységének skálájával. Például az alkalmazások általában akár millió tranzakciót, felhasználót vagy munkamenetet engednek meg. A kernel által támogatott szálak száma azonban sokkal kevesebb. Így a Thread minden felhasználó esetében a tranzakció vagy a munkamenet gyakran nem megvalósítható.
- A legtöbb egyidejű alkalmazásnak szüksége van némi szinkronizálásra a szálak között minden kéréshez. Ennek köszönhetően, drága környezetváltás történik az operációs rendszer szálai között.
Az ilyen problémák lehetséges megoldása az aszinkron egyidejű API-k használata. Gyakori példák CompletableFuture és RxJava. Feltéve, hogy az ilyen API-k nem blokkolják a kernel szálát, finomabb szemcsésségű egyidejűségi konstrukciót ad az alkalmazásnak a Java szálak tetején.
Másrészről, az ilyen API-kat nehezebb hibakeresni és integrálni a régi API-kkal. Ezért szükség van egy könnyű, párhuzamos konstrukcióra, amely független a kernel szálaitól.
4. Feladatok és ütemezők
A szál bármilyen megvalósítása, akár könnyű, akár nehéz, két konstrukciótól függ:
- Feladat (más néven folytatás) - utasítások sorozata, amely felfüggesztheti magát valamilyen blokkolási műveletnél
- Ütemező - a folytatás hozzárendeléséhez a CPU-hoz és a CPU újrabeosztásához egy szünetelt folytatásból
Jelenleg, A Java az operációs rendszer megvalósításaira támaszkodik mind a folytatás, mind az ütemező számára.
A folytatás felfüggesztése érdekében a teljes hívásköteget el kell tárolni. Hasonlóképpen, folytatáskor szerezze be a hívásköteget. Mivel a folytatások operációs rendszer megvalósítása magában foglalja a natív hívásköteget a Java híváskötegével együtt, ez súlyos lábnyomot eredményez.
Nagyobb probléma azonban az OS ütemező használata. Mivel az ütemező kernel módban fut, nincs különbség a szálak között. És minden CPU kérést ugyanúgy kezel.
Ez a fajta ütemezés az nem optimális különösen a Java alkalmazásokhoz.
Vegyünk például egy alkalmazási szálat, amely végrehajt valamilyen műveletet a kérésekkel, majd továbbadja az adatokat egy másik szálnak további feldolgozás céljából. Itt, jobb lenne mindkét szálat ugyanarra a CPU-ra ütemezni. De mivel az ütemező agnosztikus a CPU-t kérő szálon, ezt lehetetlen garantálni.
A Projekt Loom ennek megoldását javasolja felhasználói módú szálak, amelyek a folytatások és ütemezők Java futásidejű végrehajtására támaszkodnak az operációs rendszer megvalósítása helyett.
5. Rostok
Az OpenJDK legújabb prototípusaiban egy új osztályt neveztek el Rost a könyvtár mellett mutatkozik be a könyvtárban cérna osztály.
A tervezett könyvtár óta Rostok hasonló cérna, a felhasználói megvalósításnak is hasonlónak kell maradnia. Két fő különbség van:
- Rost lenne burkoljon minden feladatot egy belső felhasználói módú folytatásba. Ez lehetővé tenné a feladat számára, hogy a kernel helyett a Java futásidejében szüneteltesse és folytassa
- Dugaszolható felhasználói módú ütemező (ForkJoinPool, például) használnánk
Nézzük át részletesen ezt a két tételt.
6. Folytatások
A folytatás (vagy együttes rutin) az utasítások sorozata, amelyet a hívó később adhat ki és folytathat.
Minden folytatásnak van belépési pontja és hozampontja. A hozampont az, ahol felfüggesztették. Amikor a hívó folytatja a folytatást, a vezérlő visszatér az utolsó hozamponthoz.
Fontos felismerni hogy ez a felfüggesztés / folytatás most az operációs rendszer helyett a nyelv futásidejében fordul elő. Ezért megakadályozza a drága környezetváltást a kernelszálak között.
A szálakhoz hasonlóan a Project Loom célja a beágyazott szálak támogatása. Mivel a szálak belső folytatásokra támaszkodnak, támogatniuk kell a beágyazott folytatásokat is. Ahhoz, hogy ezt jobban megértse, vegyen fontolóra egy osztályt Folytatás amely lehetővé teszi a fészkelést:
Folytatás cont1 = új Folytatás (() -> {Folytatás cont2 = új Folytatás (() -> {// valami felfüggesztés (SCOPE_CONT_2); felfüggesztés (SCOPE_CONT_1);});});
Amint a fentiekből látható, a beágyazott folytatás felfüggesztheti önmagát vagy bármelyik befogadó folytatást egy hatókör-változó átadásával. Emiatt, néven ismertek hatókörrel folytatások.
Mivel a folytatás felfüggesztése a hívásverem tárolására is szükségessé teszi, a Loom projekt célja az is, hogy a folytatás folytatása közben könnyű veremkérést adjon hozzá.
7. Ütemező
Korábban megvitattuk az OS ütemező hiányosságait a relatable szálak ugyanazon CPU-ra történő ütemezésében.
Bár a Project Loom célja, hogy lehetővé tegye a szálakkal bővíthető ütemezők használatát, ForkJoinPool aszinkron módban lesz használva alapértelmezett ütemezőként.
ForkJoinPool működik a munkalopási algoritmus. Így minden szál megőrzi a feladatot, és a fejéből hajtja végre a feladatot. Továbbá semmilyen tétlen szál nem blokkolja, várja a feladatot, és inkább egy másik szál deque-jének farkából húzza ki.
Az egyetlen különbség az aszinkron módban az a munkásszálak ellopják a feladatot egy másik deque fejétől.
ForkJoinPool hozzáad egy másik futó feladat által ütemezett feladatot a helyi sorhoz. Ezért ugyanazon a CPU-n futtatja.
8. Következtetés
Ebben a cikkben megvitattuk a Java jelenlegi egyidejűségi modelljének problémáit és a Project Loom által javasolt változásokat.
Ennek során feladatokat és ütemezőket is meghatároztunk, és megnéztük, hogyan A Fibers és a ForkJoinPool alternatívát jelenthet a Java számára a kernelszálak használatával.