Kurzusok
/
Elixir
Elixir
/
Feladatok
/
RPN-számológép vizsgálata
RPN-számológép vizsgálata

RPN-számológép vizsgálata

Tanulófeladat

Bevezetés

Linkek

Az Elixir folyamatai elszigeteltek, és alapértelmezés szerint nem osztanak meg semmit egymással. Ha egy nem linkelt gyermekfolyamat összeomlik, a szülőfolyamatát ez nem érinti.

Ezen a viselkedésen úgy lehet változtatni, hogy a folyamatokat összelinkeljük egymással. Ha két folyamat össze van linkelve, az egyik folyamat meghibásodása átterjed a másik folyamatra. A linkek kétirányúak.

A folyamatokat létrehozhatjuk már eleve a hívó folyamathoz linkelve is a spawn_link/1 segítségével, ami atomi művelet, de linkelhetjük őket később a Process.link/1 függvénnyel is.

A folyamatok linkelése hasznos lehet párhuzamosított munkánál, amikor a munka egyes részeit nem érdemes folytatni, ha egy másik rész nem fejeződik be.

A kilépések elkapása

A linkelés folyamatok felügyeletére is használható. Ha egy folyamat elkapja a kilépéseket, nem omlik össze akkor sem, ha egy hozzá linkelt folyamat összeomlik. Ehelyett üzenetet kap az összeomlásról. Ez lehetővé teszi, hogy elegánsan kezelje az összeomlást, például úgy, hogy újraindítja az összeomlott folyamatot.

Egy folyamat beállítható úgy, hogy elkapja a kilépéseket, ha meghívjuk a Process.flag(:trap_exit, true) függvényt. Vedd figyelembe, hogy a Process.flag/2 a jelző régi értékét adja vissza, nem az új értékét.

Az az üzenet, amelyet a folyamat kap, ha egy linkelt folyamat összeomlik, illeszkedni fog a {:EXIT, from, reason} mintára, ahol a from egy PID. Ha a reason bármi más, mint a :normal atom, az azt jelenti, hogy a folyamat összeomlott, vagy erőszakosan megölték.

Taskok

A taskok olyan folyamatok, amelyek egyetlen konkrét művelet végrehajtására szolgálnak. Általában nem kommunikálnak más folyamatokkal, de visszaadhatnak egy eredményt annak a folyamatnak, amelyik elindította a taskot.

A taskokat gyakran munka párhuzamosítására használják.

async/await

Egy task elindításához a Task.async/1 függvényt használd. Ez argumentumként egy névtelen függvényt vesz át, és egy új, a hívó folyamathoz linkelt folyamatban hajtja végre. Egy %Task{} struktúrát ad vissza.

A végrehajtás eredményéhez úgy juthatsz hozzá, hogy átadod a %Task{} struktúrát a Task.await/2 függvénynek. Ez megvárja, amíg a task befejeződik, és visszaadja az eredményét. A második argumentum egy időtúllépés ezredmásodpercben, amelynek alapértéke 5000.

Vedd figyelembe, hogy a task elindítása és megvárása között a taskot indító folyamat nincs blokkolva, és más műveleteket is végezhet.

Minden Task.async/1-gyel indított taskot meg kell várni, mert üzenetet küld a hívó folyamatnak. A Task.await/2 minden task esetében csak egyszer hívható meg.

Ha egy taskot csak a mellékhatásai miatt akarsz elindítani, használd a Task.start/1 vagy a Task.start_link/1 függvényt. A Task.start/1 egy olyan taskot indít, amely nincs a hívó folyamathoz linkelve, a Task.start_link/1 pedig egy olyat, amelyik a hívó folyamathoz van linkelve. Mindkét függvény egy {:ok, pid} tuple-t ad vissza.

Utasítások

Folytatódik a munkád az Instruments of Texasnál egy kísérleti RPN-számológépen. A csapatod néhány prototípust készített, amelyeknek alapos vizsgálaton kell átesniük, hogy kiválasszák a sorozatgyártásra legalkalmasabbat.

Kétféle ellenőrzést szeretnél elvégezni.

Először egy megbízhatósági ellenőrzést, amely felismeri azokat a bemeneteket, amelyeknél a vizsgált számológép vagy összeomlik, vagy nem válaszol elég gyorsan. A hibák elkülönítéséhez minden bemenet számítását külön folyamatban kell futtatni. A hívó folyamatban a linkelés és a kilépések elkapása használható annak felismerésére, hogy a számítás befejeződött-e vagy összeomlott.

Másodszor egy helyességi ellenőrzést, amely azt vizsgálja, hogy egy adott bemenetre a számológép által visszaadott eredmény megfelel-e az elvárásoknak. Csak azok a számológépek esnek át helyességi ellenőrzésen, amelyek már átmentek a megbízhatósági ellenőrzésen, így az összeomlások nem jelentenek problémát. A műveleteket azonban egyidejűleg kell futtatni a folyamat felgyorsítása érdekében, ami tökéletes felhasználási eset az aszinkron feladatokhoz.

1. Indíts el egy megbízhatósági ellenőrzést egyetlen bemenethez

Valósítsd meg az RPNCalculatorInspection.start_reliability_check/2 függvényt. Két argumentumot kell fogadnia: egy függvényt (a számológépet) és egy bemenetet a számológép számára. Egy mapot kell visszaadnia, amely tartalmazza a bemenetet és a létrehozott folyamat PID-jét.

A létrehozott folyamat a megadott bemenettel hívja meg a megadott számológépfüggvényt. A folyamatot össze kell kapcsolni a hívó folyamattal.

RPNCalculatorInspection.start_reliability_check(fn _ -> 0 end, "2 3 +")
# => %{input: "2 3 +", pid: #PID<0.169.0>}

2. Értelmezd a megbízhatósági ellenőrzés eredményeit

Valósítsd meg az RPNCalculatorInspection.await_reliability_check_result/2 függvényt. Két argumentumot kell fogadnia. Az első argumentum egy map, amely a megbízhatósági ellenőrzés bemenetét és annak a folyamatnak a PID-jét tartalmazza, amely ezt a bemenetet ellenőrzi, az RPNCalculatorInspection.start_reliability_check/2 által visszaadott módon. A második argumentum egy map, amely akkumulátorként szolgál a különböző bemenetekhez tartozó megbízhatósági ellenőrzések eredményeihez.

A függvénynek egy kilépési üzenetre kell várnia.

Ha ugyanattól a folyamattól, amely a megbízhatósági ellenőrzést futtatja, egy :normal kilépési okkal rendelkező kilépési üzenetet kap ({:EXIT, from, reason}), akkor az eredmények mapját kell visszaadnia, az input kulcs alatt hozzáadva az :ok értéket.

Ha ugyanettől a folyamattól egy eltérő kilépési okkal rendelkező kilépési üzenetet kap, akkor az eredmények mapját kell visszaadnia, az input kulcs alatt hozzáadva az :error értéket.

Ha 100 ms-on belül nem kap semmilyen, a fenti feltételeknek megfelelő üzenetet, akkor az eredmények mapját kell visszaadnia, az input kulcs alatt hozzáadva a :timeout értéket.

# when an exit message is waiting for the process in its inbox
send(self(), {:EXIT, pid, :normal})

RPNCalculatorInspection.await_reliability_check_result(
  %{input: "5 7 -", pid: pid},
  %{}
)

# => %{"5 7 -" => :ok}

# when there are no messages in the process inbox
RPNCalculatorInspection.await_reliability_check_result(
  %{input: "3 2 *", pid: pid},
  %{"5 7 -" => :ok}
)

# => %{"5 7 -" => :ok, "3 2 *" => :timeout}

3. Futtass egyidejű megbízhatósági ellenőrzést több bemenethez

Valósítsd meg az RPNCalculatorInspection.reliability_check/2 függvényt. Két argumentumot kell fogadnia: egy függvényt (a számológépet) és a számológép bemeneteinek egy listáját.

A listán szereplő minden bemenethez új, összekapcsolt folyamatban el kell indítania a megbízhatósági ellenőrzést a start_reliability_check/2 függvénnyel. Ezután minden így elindított folyamatnál meg kell várnia annak eredményeit az await_reliability_check_result/2 függvénnyel.

Mielőtt bármilyen folyamatot elindítana, a függvénynek be kell állítania az aktuális folyamatnál a kilépések elkapását, hogy képes legyen fogadni a kilépési üzeneteket. Ezután vissza kell állítania ezt a jelzőt az eredeti értékére.

A függvénynek egy mapot kell visszaadnia az összes bemenet megbízhatósági ellenőrzésének eredményeivel.

fake_broken_calculator = fn input ->
  if String.ends_with?(input, "*"), do: raise("oops")
end

inputs = ["2 3 +", "10 3 *", "20 2 /"]

RPNCalculatorInspection.reliability_check(fake_broken_calculator, inputs)
# => %{
#       "2 3 +" => :ok,
#       "10 3 *" => :error,
#       "20 2 /" => :ok
#     }

4. Futtass egyidejű helyességi ellenőrzést több bemenethez

Valósítsd meg az RPNCalculatorInspection.correctness_check/2 függvényt. Két argumentumot kell fogadnia: egy függvényt (a számológépet) és a számológép bemeneteinek egy listáját.

A listán szereplő minden bemenethez el kell indítania egy aszinkron feladatot, amely a megadott bemenettel hívja meg a számológépet. Ezután minden így elindított feladatnál 100 ms-ig meg kell várnia annak eredményeit.

fast_cheating_calculator = fn input -> 14 end
inputs = ["13 1 +", "50 2 *", "1000 2 /"]
RPNCalculatorInspection.correctness_check(fast_cheating_calculator, inputs)
# => [14, 14, 14]
Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg
Elixir Exercism

Készen állsz elkezdeni a(z) RPN-számológép vizsgálata feladatot?

Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) Elixir nyelvet 58 fogalom168 feladat segítségével, valódi emberi mentorálással, mindez ingyen.