-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[my] Completed basics lessons and 2 advanced lessons #293
Changes from 23 commits
852a6ef
b8208da
d68d774
6573f74
18266a2
4eb4cbd
9440475
29f9bc8
aa753f0
1bfb028
9cdef5d
e052a24
9d74095
ee861e4
8627a8c
32ea908
caba10f
fda5abf
98d0939
e7b3321
9b7077c
0709c52
d3ba79c
48f5117
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,8 +14,7 @@ _Maklumbalas dan penyertaan anda amat dialu-alukan!_ | |
|
||
"Elixir ialah satu bahasa aturcara kefungsian(functional language) yang dinamik direka untuk membina aplikasi yang mudah untuk dinaiktaraf(scalable) dan mudah untuk diselenggara." - [elixir-lang.org](http:https://elixir-lang.org/) | ||
|
||
Elixir leverages the battle tested ErlangVM to build distributed and fault-tolerant systems with low-latency out of the box. | ||
Elixir meng-leverage ErlangVM untuk membina sistem yang bersifat mudah-agih(distributed) dan berdayatahan(fault-tolerant) serta mempunyai redah-kependaman(low-latency) yang disiap-pasang. | ||
Elixir menuilkan kelebihan ErlangVM untuk membina sistem yang bersifat mudah-agih(distributed) dan berdayatahan(fault-tolerant) serta mempunyai redah-kependaman(low-latency) yang disiap-pasang. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some of the other translators have started working on a Glossary for terms like these, if you want to check it out: https://github.com/doomspork/elixir-school/blob/master/GLOSSARY.md There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agreed. moving them into glossary is a good idea. I'll work on that next. |
||
|
||
__Ciri-ciri__: | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
--- | ||
layout: page | ||
title: Keserempakan(Concurrency) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm concerned these Perhaps we should move all instances of |
||
category: advanced | ||
order: 4 | ||
lang: my | ||
--- | ||
|
||
Salah satu faktor pelaris Elixir ialah sokongan kepada keserempakan(concurrency). Terima kasih kepada ErlangVM, keserempakan di dalam Elixir adalah lebih mudah dari yang dijangkakan. Model keserempakan bergantung kepada Actor, satu proses yang berkomunikasi dengan proses-proses lain melalui pengagihan mesej. | ||
|
||
Di dalam pelajaran ini kita akan lihat modul-modul keserempakan yang didatangkan dengan Elixir. Di dalam bab seterusnya kita lihat kelakuan OTP yang melaksanakan mereka. | ||
|
||
## Isi Kandungan | ||
|
||
- [Proses](#proses) | ||
- [Pengagihan Mesej](#pengagihan-mesej) | ||
- [Perangkaian Proses](#perangkaian-proses) | ||
- [Pengawasan Proses](#pengawasan-proses) | ||
- [Agents](#agents) | ||
- [Tasks](#tasks) | ||
|
||
## Proses | ||
|
||
Proses-proses di dalam ErlangVM adalah ringan dan memanafaatkan kesemua CPU apabila dijalankan. Walaupun mereka nampak seperti 'native thread', mereka sebenarnya adalah lebih ringkas dan ianya tidak janggal jika terdapat ribuan proses yang berjalan secara keserempakan di dalam aplikasi Elixir. | ||
|
||
Cara paling mudah untuk membuat satu proses baru ialah menggunakan `spawn`, yang mengambil satu fungsi tanpa nama atau fungsi bernama. Apabila kita membuat satu proses baru ia akan memulangkan satu _Process Identifier_, atau PID, sebagai pengenalan unik untuk proses itu di dalam aplikasi kita. | ||
|
||
Untuk bermula kita akan membuat satu modul dan takrifkan satu fungsi yang kita mahu jalankan: | ||
|
||
```elixir | ||
defmodule Example do | ||
def add(a, b) do | ||
IO.puts(a + b) | ||
end | ||
end | ||
|
||
iex> Example.add(2, 3) | ||
5 | ||
:ok | ||
``` | ||
|
||
Untuk menjalankan fungsi tersebut secara tak segerak(asynchronous) kita gunakan `spawn/3`: | ||
|
||
```elixir | ||
iex> spawn(Example, :add, [2, 3]) | ||
5 | ||
#PID<0.80.0> | ||
``` | ||
|
||
### Pengagihan Mesej | ||
|
||
Untuk berkomunikasi, proses-proses bergantung kepada pengagihan mesej. Terdapat dua komponen penting di dalam pengagihan mesej, `send/2` dan `receive/2`. Fungsi `send/2` mengupayakan kita untuk menghantar mesej kepada PID. Untuk mengawasi penerimaan mesej, kita gunakan `receive`. | ||
|
||
```elixir | ||
defmodule Example do | ||
def listen do | ||
receive do | ||
{:ok, "hello"} -> IO.puts "World" | ||
end | ||
end | ||
end | ||
|
||
iex> pid = spawn(Example, :listen, []) | ||
#PID<0.108.0> | ||
|
||
iex> send pid, {:ok, "hello"} | ||
World | ||
{:ok, "hello"} | ||
|
||
iex> send pid, :ok | ||
:ok | ||
``` | ||
|
||
### Perangkaian Proses | ||
|
||
Fungsi `spawn` mempunyai satu masalah iaitu untuk mengetahui apabila sesatu proses itu runtuh(crash). Untuk itu kita perlu untuk merangkaikan proses-proses kita dengan menggunakan `spawn_link`. Dua proses yang dirangkaikan akan menerima 'exit notification' dari satu sama lain: | ||
|
||
```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 | ||
``` | ||
|
||
Kadang-kadang kita tidak mahu proses yang dirangkaikan meruntuhkan proses sedia ada. Untuk itu kita perlu untk memerangkap 'exit' tersebut. 'Exit' yang diperangkap akan diterima sebagai satu mesej dalam bentuk tuple: `{: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 "Exit reason: #{reason}" | ||
end | ||
end | ||
end | ||
|
||
iex> Example.run | ||
Exit reason: kaboom | ||
:ok | ||
``` | ||
|
||
### Pengawasan Proses | ||
|
||
Bagaiana pula jika kita tidak mahu merangkaikan dua proses tetapi masih diberitahu mengenai keadaan semasa proses-proses tersebut? Untuk itu kita boleh membuat pengawasan proses dengan menggunakan `spawn_monitor`. Apabila mengawasi satu proses, kita akan mendapat satu mesej jika proses tersebut runtuh tanpa meruntuhkan sama proses semasa kita atau tanpa memerlukan 'exit' itu diperangkap. | ||
|
||
```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 "Exit reason: #{reason}" | ||
end | ||
end | ||
end | ||
|
||
iex> Example.run | ||
Exit reason: kaboom | ||
:ok | ||
``` | ||
|
||
## Agent | ||
|
||
Agent adalah sejenis peniskalaan(abstraction) proses-proses 'background' yang menyelenggara keadaan semasa(state). Mereka boleh dicapai daripada proses-proses lain dari dalam aplikasi dan nod kita. Keadaan semasa(state) Agent kita ditetapkan kepada nilai yang dipulangkan oleh fungsi-fungsi kita: | ||
|
||
```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] | ||
``` | ||
|
||
Apabila kita menamakan satu Agent, ia boleh dirujuk sebagai Agent dan tidak melalui PID-nya. | ||
|
||
```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] | ||
``` | ||
|
||
## Task | ||
|
||
'Task' menyediakan satu cara untk menjalankan satu fungsi di 'background' dan menerima nilai yang dipulangkan kemudian. Ianya amat berguna apabila menguruskan operasi-operasi yang berat tanpa merencatkan perjalanan aplikasi. | ||
|
||
```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>} | ||
|
||
# Do some work | ||
|
||
iex> Task.await(task) | ||
4000 | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
--- | ||
layout: page | ||
title: Kesalingbolehgunaan(Interoperability) Dengan Erlang | ||
category: advanced | ||
order: 1 | ||
lang: my | ||
--- | ||
|
||
Salah satu faedah tambahan daripada membina di atas ErlangVM ialah lambakan pustaka sedia ada yang tersedia untuk kita. Kesalingbolehgunaan(Interoperability) mengupayakan kita untuk menuilkan(leverage) pustaka-pustaka tersebut dan pustaka rasmi Erlang daripada kod Elixir kita. Di dalam pelajaran ini kita akan melihat bagaimana untuk mencapai kefungsian di dalam pustaka rasmi dan juga pustaka-pustaka pihak ketiga Erlang. | ||
|
||
## Isi Kandungan | ||
|
||
- [Pustaka Rasmi](#pustaka-rasmi) | ||
- [Pakej Erlang](#pakej-erlang) | ||
- [Perbezaan Nyata](#perbezaan-nyata) | ||
- [Atom](#atom) | ||
- [String](#string) | ||
- [Pembolehubah](#pembolehubah) | ||
|
||
|
||
## Pustaka Rasmi | ||
|
||
Pustaka rasmi Erlang yang besar boleh dicapai dari mana-mana kod Elixir di dalam aplikasi kita. Modul-modul Erlang diwakilkan oleh atom-atom berhuruf kecil seperti `:os` dan `:timer`. | ||
|
||
Mari kita gunakan `:timer.tc` untuk mengukur masa yang digunakan untuk menjalankan satu fungsi: | ||
|
||
```elixir | ||
defmodule Example do | ||
def timed(fun, args) do | ||
{time, result} = :timer.tc(fun, args) | ||
IO.puts "Time: #{time}ms" | ||
IO.puts "Result: #{result}" | ||
end | ||
end | ||
|
||
iex> Example.timed(fn (n) -> (n * n) * n end, [100]) | ||
Time: 8ms | ||
Result: 1000000 | ||
``` | ||
|
||
Sila lihat [Erlang Reference Manual](http:https://erlang.org/doc/apps/stdlib/) untuk mendapatkan senarai lengkap modul-modul yang disediakan. | ||
|
||
## Pakej Erlang | ||
|
||
Di dalam pelajaran lepas kita telah melihat Mix dan cara-cara menguruskan komponen-komponen sokongan(dependencies). Pustaka Erlang juga boleh diuruskan dengan cara yang sama. Jika pustaka Erlang yang diperlukan itu masih belum dimasukkan ke dalam [Hex](https://hex.pm), anda boleh membuat rujukan terus ke repositori git: | ||
|
||
```elixir | ||
def deps do | ||
[{:png, github: "yuce/png"}] | ||
end | ||
``` | ||
|
||
Sekarang kita boleh mencapai pustaka Erlang tersebut: | ||
|
||
```elixir | ||
png = :png.create(#{:size => {30, 30}, | ||
:mode => {:indexed, 8}, | ||
:file => file, | ||
:palette => palette}), | ||
``` | ||
|
||
## Perbezaan Nyata | ||
|
||
Oleh kerana sekarang kita telah tahu bagaimana untuk menggunakan pustaka Elixir kita patut melihat beberapa isu yang didatangkan oleh kesalingbolehgunaan dengan Erlang. | ||
|
||
### Atom | ||
|
||
Atom-atom Erlang nampak lebih kurang sama dengan atom Elixir, cuma tanpa tanda titik bertindih (`:`). Mereka diwakili oleh string huruf kecil dan garis bawah. | ||
|
||
Elixir: | ||
|
||
```elixir | ||
:example | ||
``` | ||
|
||
Erlang: | ||
|
||
```erlang | ||
example. | ||
``` | ||
|
||
### String | ||
|
||
Apabila kita bercakap mengenai string di dalam Elixir, kita merujuk kepada 'UTF-8 encoded binaries'. Di dalam Erlang, string masih ditandakan menggunakan tanda ungkapan berganda ("") tetapi merujuk kepada list aksara. | ||
|
||
Elixir: | ||
|
||
```elixir | ||
iex> is_list('Example') | ||
true | ||
iex> is_list("Example") | ||
false | ||
iex> is_binary("Example") | ||
true | ||
iex> <<"Example">> === "Example" | ||
true | ||
``` | ||
|
||
Erlang: | ||
|
||
```erlang | ||
1> is_list('Example'). | ||
false | ||
2> is_list("Example"). | ||
true | ||
3> is_binary("Example"). | ||
false | ||
4> is_binary(<<"Example">>). | ||
true | ||
``` | ||
|
||
Penting untuk diperhatikan bahawa banyak pustaka Erlang yang lama mungkin tidak menyokong 'binary' jadi kita perlu menukarkan string Elixir kepada list aksara. Nasib baik ianya mudah untuk dilakukan dengan menggunakan fungsi `to_char_list/1`: | ||
|
||
```elixir | ||
iex> :string.words("Hello World") | ||
** (FunctionClauseError) no function clause matching in :string.strip_left/2 | ||
(stdlib) string.erl:380: :string.strip_left("Hello World", 32) | ||
(stdlib) string.erl:378: :string.strip/3 | ||
(stdlib) string.erl:316: :string.words/2 | ||
|
||
iex> "Hello World" |> to_char_list |> :string.words | ||
2 | ||
``` | ||
|
||
### Pembolehubah | ||
|
||
Elixir: | ||
|
||
```elixir | ||
iex> x = 10 | ||
10 | ||
|
||
iex> x1 = x + 10 | ||
20 | ||
``` | ||
|
||
Erlang: | ||
|
||
```erlang | ||
1> X = 10. | ||
10 | ||
|
||
2> X1 = X + 1. | ||
11 | ||
``` | ||
|
||
Itu sahaja! Menuilkan kelebihan Erlang dari dalam aplikasi Elixir adalah cukup mudah dan secara tidak lansung menggandakan jumlah pustaka yang tersedia untuk kita. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need this change, can you remove this file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it was edited due to merge error. how do I remove this file from this commit?