Οι διαδικασίες της Elixir είναι απομονωμένες και δε μοιράζονται τίποτα από προεπιλογή. Όταν μια θυγατρική διαδικασία που δεν είναι συνδεδεμένη καταρρέει, η γονική της διαδικασία δεν επηρεάζεται.
Αυτή η συμπεριφορά μπορεί να αλλάξει με τη σύνδεση των διαδικασιών μεταξύ τους. Αν δύο διαδικασίες είναι συνδεδεμένες, μια αποτυχία στη μία διαδικασία θα διαδοθεί στην άλλη. Οι σύνδεσμοι είναι αμφίδρομοι.
Οι διαδικασίες μπορούν να δημιουργηθούν ήδη συνδεδεμένες με την καλούσα διαδικασία χρησιμοποιώντας το spawn_link/1, το οποίο είναι μια ατομική λειτουργία, ή μπορούν να συνδεθούν αργότερα με το Process.link/1.
Η σύνδεση διαδικασιών μπορεί να είναι χρήσιμη όταν κάνεις παράλληλη εργασία, όταν κάθε κομμάτι εργασίας δεν θα έπρεπε να συνεχιστεί σε περίπτωση που κάποιο άλλο κομμάτι αποτύχει να ολοκληρωθεί.
Η σύνδεση μπορεί επίσης να χρησιμοποιηθεί για την εποπτεία διαδικασιών. Αν μια διαδικασία παγιδεύει εξόδους, δε θα καταρρεύσει όταν καταρρεύσει μια διαδικασία με την οποία είναι συνδεδεμένη. Αντ' αυτού θα λάβει ένα μήνυμα για την κατάρρευση. Αυτό της επιτρέπει να χειριστεί την κατάρρευση με κομψό τρόπο, για παράδειγμα επανεκκινώντας τη διαδικασία που κατέρρευσε.
Μια διαδικασία μπορεί να ρυθμιστεί ώστε να παγιδεύει εξόδους καλώντας το Process.flag(:trap_exit, true). Σημείωσε ότι το Process.flag/2 επιστρέφει την παλιά τιμή της σημαίας, όχι τη νέα.
Το μήνυμα που θα σταλεί στη διαδικασία σε περίπτωση που καταρρεύσει μια συνδεδεμένη διαδικασία θα ταιριάζει με το μοτίβο {:EXIT, from, reason}, όπου το from είναι ένα PID. Αν το reason είναι οτιδήποτε άλλο εκτός από το άτομο :normal, αυτό σημαίνει ότι η διαδικασία κατέρρευσε ή σκοτώθηκε βίαια.
Οι εργασίες είναι διαδικασίες που προορίζονται να εκτελέσουν μία συγκεκριμένη λειτουργία. Συνήθως δεν επικοινωνούν με άλλες διαδικασίες, αλλά μπορούν να επιστρέψουν ένα αποτέλεσμα στη διαδικασία που ξεκίνησε την εργασία.
Οι εργασίες χρησιμοποιούνται συνήθως για την παραλληλοποίηση εργασίας.
async/await
Για να ξεκινήσεις μια εργασία, χρησιμοποίησε το Task.async/1. Παίρνει μια ανώνυμη συνάρτηση ως όρισμα και την εκτελεί σε μια νέα διαδικασία που είναι συνδεδεμένη με τη διαδικασία που την κάλεσε. Επιστρέφει ένα struct %Task{}.
Για να πάρεις το αποτέλεσμα της εκτέλεσης, πέρασε το struct %Task{} στο Task.await/2. Θα περιμένει να ολοκληρωθεί η εργασία και θα επιστρέψει το αποτέλεσμά της. Το δεύτερο όρισμα είναι ένα χρονικό όριο σε χιλιοστά του δευτερολέπτου, με προεπιλογή το 5000.
Σημείωσε ότι μεταξύ της εκκίνησης της εργασίας και της αναμονής της, η διαδικασία που ξεκίνησε την εργασία δεν είναι αποκλεισμένη και μπορεί να κάνει άλλες λειτουργίες.
Κάθε εργασία που ξεκινά με το Task.async/1 θα πρέπει να αναμένεται, γιατί θα στείλει ένα μήνυμα στη διαδικασία που την κάλεσε. Το Task.await/2 μπορεί να κληθεί για κάθε εργασία μόνο μία φορά.
start/start_link
Αν θέλεις να ξεκινήσεις μια εργασία μόνο για παρενέργειες, χρησιμοποίησε το Task.start/1 ή το Task.start_link/1. Το Task.start/1 θα ξεκινήσει μια εργασία που δεν είναι συνδεδεμένη με τη διαδικασία που την καλεί, και το Task.start_link/1 θα ξεκινήσει μια εργασία που είναι συνδεδεμένη με τη διαδικασία που την καλεί. Και οι δύο συναρτήσεις επιστρέφουν ένα tuple {:ok, pid}.
Η εργασία σου στην Instruments of Texas πάνω σε μια πειραματική αριθμομηχανή RPN συνεχίζεται. Η ομάδα σου έχει φτιάξει μερικά πρωτότυπα που πρέπει να περάσουν από διεξοδικό έλεγχο, ώστε να επιλεγεί το καλύτερο για μαζική παραγωγή.
Θέλεις να πραγματοποιήσεις δύο είδη ελέγχων.
Πρώτον, έναν έλεγχο αξιοπιστίας που θα εντοπίζει εισόδους για τις οποίες η αριθμομηχανή υπό έλεγχο είτε καταρρέει είτε δεν αποκρίνεται αρκετά γρήγορα. Για να απομονωθούν οι αστοχίες, οι υπολογισμοί για κάθε είσοδο πρέπει να εκτελούνται σε ξεχωριστή διεργασία. Η σύνδεση και η παγίδευση εξόδων στην καλούσα διεργασία μπορούν να χρησιμοποιηθούν για να διαπιστωθεί αν ο υπολογισμός ολοκληρώθηκε ή κατέρρευσε.
Δεύτερον, έναν έλεγχο ορθότητας που θα εξετάζει αν, για μια δεδομένη είσοδο, το αποτέλεσμα που επιστρέφει η αριθμομηχανή είναι το αναμενόμενο. Μόνο οι αριθμομηχανές που έχουν ήδη περάσει τον έλεγχο αξιοπιστίας θα υποβληθούν σε έλεγχο ορθότητας, οπότε οι καταρρεύσεις δεν αποτελούν πρόβλημα. Ωστόσο, οι πράξεις θα πρέπει να εκτελούνται ταυτόχρονα για να επιταχυνθεί η διαδικασία, γεγονός που το καθιστά ιδανική περίπτωση χρήσης για ασύγχρονες εργασίες.
Υλοποίησε τη συνάρτηση RPNCalculatorInspection.start_reliability_check/2. Θα πρέπει να δέχεται 2 ορίσματα, μια συνάρτηση (την αριθμομηχανή) και μια είσοδο για την αριθμομηχανή. Θα πρέπει να επιστρέφει έναν χάρτη που περιέχει την είσοδο και το PID της διεργασίας που δημιουργήθηκε.
Η διεργασία που δημιουργήθηκε θα πρέπει να καλέσει τη δεδομένη συνάρτηση αριθμομηχανής με τη δεδομένη είσοδο. Η διεργασία θα πρέπει να συνδεθεί με την καλούσα διεργασία.
RPNCalculatorInspection.start_reliability_check(fn _ -> 0 end, "2 3 +")
# => %{input: "2 3 +", pid: #PID<0.169.0>}
Υλοποίησε τη συνάρτηση RPNCalculatorInspection.await_reliability_check_result/2. Θα πρέπει να δέχεται δύο ορίσματα. Το πρώτο όρισμα είναι ένας χάρτης με την είσοδο του ελέγχου αξιοπιστίας και το PID της διεργασίας που εκτελεί τον έλεγχο αξιοπιστίας για αυτή την είσοδο, όπως τον επιστρέφει η RPNCalculatorInspection.start_reliability_check/2. Το δεύτερο όρισμα είναι ένας χάρτης που χρησιμεύει ως συσσωρευτής για τα αποτελέσματα ελέγχων αξιοπιστίας με διαφορετικές εισόδους.
Η συνάρτηση θα πρέπει να περιμένει ένα μήνυμα εξόδου.
Αν λάβει ένα μήνυμα εξόδου ({:EXIT, from, reason}) με αιτία :normal από την ίδια διεργασία που εκτελεί τον έλεγχο αξιοπιστίας, θα πρέπει να επιστρέφει τον χάρτη αποτελεσμάτων με την τιμή :ok να προστίθεται στο κλειδί input.
Αν λάβει ένα μήνυμα εξόδου με διαφορετική αιτία από την ίδια διεργασία που εκτελεί τον έλεγχο αξιοπιστίας, θα πρέπει να επιστρέφει τον χάρτη αποτελεσμάτων με την τιμή :error να προστίθεται στο κλειδί input.
Αν δεν λάβει κανένα μήνυμα που να πληροί αυτά τα κριτήρια μέσα σε 100ms, θα πρέπει να επιστρέφει τον χάρτη αποτελεσμάτων με την τιμή :timeout να προστίθεται στο κλειδί input.
# 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}
Υλοποίησε τη συνάρτηση RPNCalculatorInspection.reliability_check/2. Θα πρέπει να δέχεται 2 ορίσματα, μια συνάρτηση (την αριθμομηχανή) και μια λίστα με εισόδους για την αριθμομηχανή.
Για κάθε είσοδο στη λίστα, θα πρέπει να ξεκινά τον έλεγχο αξιοπιστίας σε μια νέα συνδεδεμένη διεργασία χρησιμοποιώντας τη start_reliability_check/2. Στη συνέχεια, για κάθε διεργασία που ξεκίνησε με αυτόν τον τρόπο, θα πρέπει να περιμένει τα αποτελέσματά της χρησιμοποιώντας τη await_reliability_check_result/2.
Πριν ξεκινήσει οποιαδήποτε διεργασία, η συνάρτηση πρέπει να ορίσει τη σημαία παγίδευσης εξόδων στην τρέχουσα διεργασία, ώστε να μπορεί να λαμβάνει μηνύματα εξόδου. Έπειτα, θα πρέπει να επαναφέρει αυτή τη σημαία στην αρχική της τιμή.
Η συνάρτηση θα πρέπει να επιστρέφει έναν χάρτη με τα αποτελέσματα των ελέγχων αξιοπιστίας όλων των εισόδων.
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
# }
Υλοποίησε τη συνάρτηση RPNCalculatorInspection.correctness_check/2. Θα πρέπει να δέχεται 2 ορίσματα, μια συνάρτηση (την αριθμομηχανή) και μια λίστα με εισόδους για την αριθμομηχανή.
Για κάθε είσοδο στη λίστα, θα πρέπει να ξεκινά μια ασύγχρονη εργασία που θα καλεί την αριθμομηχανή με τη δεδομένη είσοδο. Στη συνέχεια, για κάθε εργασία που ξεκίνησε με αυτόν τον τρόπο, θα πρέπει να περιμένει τα αποτελέσματά της για 100ms.
fast_cheating_calculator = fn input -> 14 end
inputs = ["13 1 +", "50 2 *", "1000 2 /"]
RPNCalculatorInspection.correctness_check(fast_cheating_calculator, inputs)
# => [14, 14, 14]
Γράψου στο Exercism για να μάθεις και να κατακτήσεις Elixir με 58 έννοιες168 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.