forked from elixirschool/elixirschool
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
greek translations: advanced (elixirschool#626)
* translations/advanced * greek advanced/otp-concurrency translation
- Loading branch information
Showing
5 changed files
with
776 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
--- | ||
layout: page | ||
title: Συγχρονισμός | ||
category: advanced | ||
order: 4 | ||
lang: gr | ||
--- | ||
|
||
Ένα από τα σημαντικά σημεία της Elixir είναι η υποστήριξή της για συγχρονισμό. Χάρη στην Εικονική Μηχανή της Erlang (BEAM), ο συγχρονισμός στην Elixir είναι πιο εύκολο από το αναμενόμενο. Το μοντέλο συγχρονισμού στηρίζεται στους Ηθοποιούς, μια περιορισμένη διεργασία που επικοινωνεί με άλλες διεργασίες μέσω αποστολής μηνυμάτων. | ||
|
||
Σε αυτό το μάθημα θα δούμε τις ενότητες συγχρονισμού που έρχονται με την Elixir. Στο επόμενο κεφάλαιο θα καλύψουμε τις συμπεριφορές OTP που τις υλοποιούν. | ||
|
||
{% include toc.html %} | ||
|
||
## Διεργασίες | ||
|
||
Οι διεργασίες στην εικονική μηχανή της Erlang είναι ελαφριές και τρέχουν σε όλους τους επεξεργαστές. Παρόλο που φαίνονται σαν τοπικά νήματα, είναι πιο απλές και είναι συνηθισμένο να έχουμε χιλιάδες συγχρονισμένες διεργασίες σε μια εφαρμογή Elixir. | ||
|
||
Ο πιο απλός τρόπος να δημιουγήσουμε μια νέα διεργασία είναι η `spawn`, η οποία δέχεται είτε μια ανώνυμη ή μια ονομασμένη συνάρτηση. Όταν δημιουργούμε μια νά διεργασία επιστρέφει ένα _Προσδιοριστικό Διεργασία_, ή PID για να την προσδιορίζει μοναδικά στην εφαρμογή μας. | ||
|
||
Για να ξεκινήσουμε θα δημιουργήσουμε μια ενότητα και θα ορίσουμε μια συνάρτηση που θα θέλαμε να τρέξουμε: | ||
|
||
```elixir | ||
defmodule Example do | ||
def add(a, b) do | ||
IO.puts(a + b) | ||
end | ||
end | ||
|
||
iex> Example.add(2, 3) | ||
5 | ||
:ok | ||
``` | ||
|
||
Για να τρέξουμε τη συνάρτηση ασύγχρονα θα χρησιμοποιήσουμε την `spawn/3`: | ||
|
||
```elixir | ||
iex> spawn(Example, :add, [2, 3]) | ||
5 | ||
#PID<0.80.0> | ||
``` | ||
|
||
### Αποστολή Μηνυμάτων | ||
|
||
Για να επικοινωνήσουν, οι διεργασίες στηρίζονται στο πέρασμα μηνυμάτων. Υπάρχουν δύο κύρια συστατικά σε αυτό: οι `send/2` και `receive`. Η συνάρτηση `send/2` μας επιτρέπει να στέλνουμε μηνύματα σε PID. Για να τα λαμβάνουμε χρησιμοποιούμε την `receive` για να αντιπαραβάλουμε μηνύματα. Αν δεν βρεθεί ταίρι η εκτέλλεση συνεχίζει απερίσπαστη. | ||
|
||
```elixir | ||
defmodule Example do | ||
def listen do | ||
receive do | ||
{:ok, "γεια"} -> IO.puts "Κόσμε" | ||
end | ||
end | ||
end | ||
|
||
iex> pid = spawn(Example, :listen, []) | ||
#PID<0.108.0> | ||
|
||
iex> send pid, {:ok, "γεια"} | ||
World | ||
{:ok, "γεια"} | ||
|
||
iex> send pid, :ok | ||
:ok | ||
``` | ||
|
||
### Σύνδεση Διεργασιών | ||
|
||
Ένα πρόβλημα την `spawn` είναι όταν πρέπει να ξέρουμε πότε μια διεργασία κρασάρει. Για αυτό πρέπει να συνδέσουμε τις διεργασίες μας με την χρήση της `spawn_link`. Δύο συνδεδεμένες διεργασίες θα λάβουν ειδοποιήσεις εξόδου η μία από την άλλη: | ||
|
||
```elixir | ||
defmodule Example do | ||
def explode, do: exit(:kaboom) | ||
end | ||
|
||
iex> spawn(Example, :explode, []) | ||
#PID<0.66.0> | ||
|
||
iex> spawn_link(Example, :explode, []) | ||
** (EXIT from #PID<0.57.0>) :kaboom | ||
``` | ||
|
||
Μερικές φορές δεν θέλουμε τις συνδεδεμένες διεργασίες μας να κρασάρουν την τρέχουσα. Για αυτό πρέπει να παγιδεύσουμε τις εξόδους. Όταν παγιδεύουμε τις εξόδους αυτές θα ληφθούν σαν ένα μήνυμα με μορφή τούπλας: `{:EXIT, from_pid, reason}`. | ||
|
||
```elixir | ||
defmodule Example do | ||
def explode, do: exit(:kaboom) | ||
def run do | ||
Process.flag(:trap_exit, true) | ||
spawn_link(Example, :explode, []) | ||
|
||
receive do | ||
{:EXIT, from_pid, reason} -> IO.puts "Λόγος εξόδου: #{reason}" | ||
end | ||
end | ||
end | ||
|
||
iex> Example.run | ||
Λόγος εξόδου: kaboom | ||
:ok | ||
``` | ||
|
||
### Παρακολούθηση Διεργασιών | ||
|
||
Τι γίνεται όταν δεν θέλουμε να συνδέσουμε δύο διεργασίες αλλά παρόλα αυτά να ενημερωνόμαστε; Για αυτό μπορούμε να χρησιμοποιήσουμε την παρακολούθηση διεργασίας με την `spawn_monitor`. Όταν παρακολουθούμε μια διεργασία λαμβάνουμε ένα μήνυμα αν η διεργασία κρασάρει χωρίς να κρασάρει η τρέχουσα διεργασία ή να παγιδεύσουμε τις εξόδους. | ||
|
||
```elixir | ||
defmodule Example do | ||
def explode, do: exit(:kaboom) | ||
def run do | ||
{pid, ref} = spawn_monitor(Example, :explode, []) | ||
|
||
receive do | ||
{:DOWN, ref, :process, from_pid, reason} -> IO.puts "Λόγος Εξόδου: #{reason}" | ||
end | ||
end | ||
end | ||
|
||
iex> Example.run | ||
Exit reason: kaboom | ||
:ok | ||
``` | ||
|
||
## Πράκτορες | ||
|
||
Οι πράκτορες είναι μια αφαίρεση γύρω από την διατήρηση κατάστασης των διεργασιών παρασκηνίου. Μπορούμε να έχουμε πρόσβαση σε αυτές από άλλες διεργασίες μέσα από την εφαρμογή και τον κόμβο μας. Η κατάσταση του Πράκτορά μας ορίζεται σαν η τιμή επιστροφής της συνάρτησής μας: | ||
|
||
```elixir | ||
iex> {:ok, agent} = Agent.start_link(fn -> [1, 2, 3] end) | ||
{:ok, #PID<0.65.0>} | ||
|
||
iex> Agent.update(agent, fn (state) -> state ++ [4, 5] end) | ||
:ok | ||
|
||
iex> Agent.get(agent, &(&1)) | ||
[1, 2, 3, 4, 5] | ||
``` | ||
|
||
Όταν ονομάζουμε έναν Πράκτορα μπορούμε να αναφερθούμε σε αυτόν αντί στο PID του: | ||
|
||
```elixir | ||
iex> Agent.start_link(fn -> [1, 2, 3] end, name: Numbers) | ||
{:ok, #PID<0.74.0>} | ||
|
||
iex> Agent.get(Numbers, &(&1)) | ||
[1, 2, 3] | ||
``` | ||
|
||
## Εργασίες | ||
|
||
Οι Εργασίες παρέχουν ένα τρόπο να εκτελέσουμε μια συνάρτηση στο παρασκήνιο και να λάβουμε την τιμή επιστροφής της αργότερα. Μπορούν να είναι ιδιαίτερα χρήσιμες όταν χειρίζονται ακριβές λειτουργίες χωρίς να μπλοκάρουν την εκτέλεση της εφαρμογής. | ||
|
||
```elixir | ||
defmodule Example do | ||
def double(x) do | ||
:timer.sleep(2000) | ||
x * 2 | ||
end | ||
end | ||
|
||
iex> task = Task.async(Example, :double, [2000]) | ||
%Task{pid: #PID<0.111.0>, ref: #Reference<0.0.8.200>} | ||
|
||
# Κάντε κάτι άλλο | ||
|
||
iex> Task.await(task) | ||
4000 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
--- | ||
layout: page | ||
title: Διαλειτουργικότητα με την Erlang | ||
category: advanced | ||
order: 1 | ||
lang: gr | ||
--- | ||
|
||
Ένα από τα βασικά πλεονεκτήματα του να χτίζεις πάνω στην εικονική μηχανή της Erlang (BEAM) είναι η πληθώρα των υπάρχουσων βιβλιοθηκών που μας είναι διαθέσιμες. Η διαλειτουργικότητα μας επιτρέπει να αξιοποιούμε αυτές τις βιβλιοθήκες και την βασική βιβλιοθήκη της Erlang από τον κώδικά μας σε Elixir. Σε αυτό το μάθημα θα δούμε πως να έχουμε πρόσβαση σε λειτουργίες της βασικής βιβλιοθήκης και σε πακέτα τρίτων της Erlang. | ||
|
||
{% include toc.html %} | ||
|
||
## Βασική Βιβλιοθήκη | ||
|
||
Η εκτενής βασική βιβλιοθήκη της Erlang μπορεί να προσεγγιστεί από οποιοδήποτε κώδικα Elixir στην εφαρμογή μας. Οι ενότητες της Erlang παρουσιάζονται σαν άτομα με μικρά γράμματα όπως η `:os` και `:timer`. | ||
|
||
Ας χρησιμοποιήσουμε την `:timer.tc` για να χρονομετρήσουμε την εκτέλεση μιας δοθείσας συνάρτησης: | ||
|
||
```elixir | ||
defmodule Example do | ||
def timed(fun, args) do | ||
{time, result} = :timer.tc(fun, args) | ||
IO.puts "Χρόνος: #{time}ms" | ||
IO.puts "Αποτέλεσμα: #{result}" | ||
end | ||
end | ||
|
||
iex> Example.timed(fn (n) -> (n * n) * n end, [100]) | ||
Χρόνος: 8ms | ||
Αποτέλεσμα: 1000000 | ||
``` | ||
|
||
Για μια πλήρη λίστα των διαθέσιμων ενοτήτων, δείτε το [Εγχειρίδιο Αναφοράς της Erlang](http:https://erlang.org/doc/apps/stdlib/). | ||
|
||
## Πακέτα Erlang | ||
|
||
Σε ένα προηγούμενο μάθημα καλύψαμε το Mix και τη διαχείριση των εξαρτήσεων μας. Η προσθήκη βιβλιοθηκών της Erlang δουλεύει με τον ίδιο τρόπο. Σε περίπτωση που η βιβλιοθήκη της Erlang δεν έχει ανέβει στο [Hex](https://hex.pm), μπορείτε να αναφερθείτε στο αποθετήριο git: | ||
|
||
```elixir | ||
def deps do | ||
[{:png, github: "yuce/png"}] | ||
end | ||
``` | ||
|
||
Τώρα μπορούμε να έχουμε πρόσβαση στην βιβλιοθήκη της Erlang: | ||
|
||
```elixir | ||
png = :png.create(%{:size => {30, 30}, | ||
:mode => {:indexed, 8}, | ||
:file => file, | ||
:palette => palette}) | ||
``` | ||
|
||
## Αξιοσημείωτες Διαφορές | ||
|
||
Τώρα που ξέρουμε πως να χρησιμοποιήσουμε την Erlang θα πρέπει να καλύψουμε μερικά σημαντικά σημεία που προκύπτουν από την διαλειτουργικότητα με την Erlang. | ||
|
||
### Άτομα | ||
|
||
Τα άτομα της Erlang δείχνουν σχεδόν ίδια με τα αντίστοιχα της Elixir χωρίς την άνω-κάτω τελεία (`:`). Παρουσιάζονται με αλφαριθμητικά μικρών γραμμάτων και κάτω πάυλες: | ||
|
||
Elixir: | ||
|
||
```elixir | ||
:example | ||
``` | ||
|
||
Erlang: | ||
|
||
```erlang | ||
example. | ||
``` | ||
|
||
### Αλφαριθμητικά | ||
|
||
Στην Elixir όταν συζητάμε για αλφαριθμητικά εννοούμε δυαδικά κωδικοποιημένα σε UTF-8. Στην Erlang, τα αλφαριθμητικά χρησιμοποιούν διπλά εισαγωγικά αλλά αναφέρονται σαν λίστες χαρακτήρων: | ||
|
||
Elixir: | ||
|
||
```elixir | ||
iex> is_list('Παράδειγμα') | ||
true | ||
iex> is_list("Παράδειγμα") | ||
false | ||
iex> is_binary("Παράδειγμα") | ||
true | ||
iex> <<"Παράδειγμα">> === "Παράδειγμα" | ||
true | ||
``` | ||
|
||
Erlang: | ||
|
||
```erlang | ||
1> is_list('Παράδειγμα'). | ||
false | ||
2> is_list("Παράδειγμα"). | ||
true | ||
3> is_binary("Παράδειγμα"). | ||
false | ||
4> is_binary(<<"Παράδειγμα">>). | ||
true | ||
``` | ||
|
||
Είναι σημαντικό να σημειώσουμε ότι πολλές παλαιότερες βιβλιοθήκες της Erlang μπορεί να μην υποστηρίζουν τα δυαδικά, έτσι πρέπει να μετατρέψουμε τα αλφαριθμητικά της Elixir σε λίστες χαρακτήρων. Ευτυχώς αυτό είναι εύκολο να γίνει με την συνάρτηση `to_char_list/1`: | ||
|
||
```elixir | ||
iex> :string.words("Γειά σου Κόσμε") | ||
** (FunctionClauseError) no function clause matching in :string.strip_left/2 | ||
(stdlib) string.erl:380: :string.strip_left("Γειά σου κόσμε", 32) | ||
(stdlib) string.erl:378: :string.strip/3 | ||
(stdlib) string.erl:316: :string.words/2 | ||
|
||
iex> "Γειά σου Κόσμε" |> to_char_list |> :string.words | ||
3 | ||
``` | ||
|
||
### Μεταβλητές | ||
|
||
Elixir: | ||
|
||
```elixir | ||
iex> x = 10 | ||
10 | ||
|
||
iex> x1 = x + 10 | ||
20 | ||
``` | ||
|
||
Erlang: | ||
|
||
```erlang | ||
1> X = 10. | ||
10 | ||
|
||
2> X1 = X + 1. | ||
11 | ||
``` | ||
|
||
Αυτό ήταν! Η αξιοποίηση της Erlang μέσα από τις Elixir εφαρμογές μας είναι εύκολη και διπλασιάζει με αποτελεσματικό τρόπο τις βιβλιοθήκες που μας είναι διαθέσιμες. |
Oops, something went wrong.