rabbit-slide-niku-yapc-hokkaido-2016-eve-naruhodo-erlang-process 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rabbit +1 -0
- data/README.md +24 -0
- data/Rakefile +17 -0
- data/config.yaml +19 -0
- data/naruhounix-cover.jpg +0 -0
- data/pdf/yapc-hokkaido-2016-eve-naruhodo-erlang-process-yapc-hokkaido-2016-eve-naruhodo-erlang-process.pdf +0 -0
- data/yapc-hokkaido-2016-eve-naruhodo-erlang-process.md +655 -0
- metadata +66 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c94ebf71a86f88aed81863cfac708d0860542826
|
4
|
+
data.tar.gz: de5a55679ce2ed7c8fc9a89d6a9031a9306437f7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 27def99ad67f1ade53f006a40b45aa4e630927ae81adbcda817530a36c46302c02c5407c2d623adccf72656507dd90ffe25d3b7447dd2b046ac0d88f00f58d64
|
7
|
+
data.tar.gz: 8d8e2bf19f3b80225ca0a801a8fdb2cc9ddbdf191bf24a3c014dabddb117653bf37fdd8beb02bc5dff82862f567231fbbc636aa18517860bb988b8f8f4245821
|
data/.rabbit
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
yapc-hokkaido-2016-eve-naruhodo-erlang-process.md
|
data/README.md
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# なるほど Erlang プロセス
|
2
|
+
|
3
|
+
[YAPC::Hokkaido 2016 SAPPORO 前夜祭](http://passmarket.yahoo.co.jp/event/show/detail/0170cmyfxi8j.html) での
|
4
|
+
「なるほどErlangプロセス」発表資料
|
5
|
+
|
6
|
+
## 作者向け
|
7
|
+
|
8
|
+
### 表示
|
9
|
+
|
10
|
+
rake
|
11
|
+
|
12
|
+
### 公開
|
13
|
+
|
14
|
+
rake publish
|
15
|
+
|
16
|
+
## 閲覧者向け
|
17
|
+
|
18
|
+
### インストール
|
19
|
+
|
20
|
+
gem install rabbit-slide-niku-yapc-hokkaido-2016-eve-naruhodo-erlang-process
|
21
|
+
|
22
|
+
### 表示
|
23
|
+
|
24
|
+
rabbit rabbit-slide-niku-yapc-hokkaido-2016-eve-naruhodo-erlang-process.gem
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require "rabbit/task/slide"
|
2
|
+
|
3
|
+
# Edit ./config.yaml to customize meta data
|
4
|
+
|
5
|
+
spec = nil
|
6
|
+
Rabbit::Task::Slide.new do |task|
|
7
|
+
spec = task.spec
|
8
|
+
# spec.files += Dir.glob("doc/**/*.*")
|
9
|
+
# spec.files -= Dir.glob("private/**/*.*")
|
10
|
+
# spec.add_runtime_dependency("YOUR THEME")
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "Tag #{spec.version}"
|
14
|
+
task :tag do
|
15
|
+
sh("git", "tag", "-a", spec.version.to_s, "-m", "Publish #{spec.version}")
|
16
|
+
sh("git", "push", "--tags")
|
17
|
+
end
|
data/config.yaml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
---
|
2
|
+
id: yapc-hokkaido-2016-eve-naruhodo-erlang-process
|
3
|
+
base_name: yapc-hokkaido-2016-eve-naruhodo-erlang-process
|
4
|
+
tags: []
|
5
|
+
presentation_date:
|
6
|
+
version: 1.0.0
|
7
|
+
licenses: []
|
8
|
+
slideshare_id:
|
9
|
+
speaker_deck_id:
|
10
|
+
ustream_id:
|
11
|
+
vimeo_id:
|
12
|
+
youtube_id:
|
13
|
+
author:
|
14
|
+
markup_language: :markdown
|
15
|
+
name: niku
|
16
|
+
email: niku@niku.name
|
17
|
+
rubygems_user: niku
|
18
|
+
slideshare_user:
|
19
|
+
speaker_deck_user:
|
Binary file
|
Binary file
|
@@ -0,0 +1,655 @@
|
|
1
|
+
# なるほど Erlang プロセス
|
2
|
+
|
3
|
+
author
|
4
|
+
niku
|
5
|
+
date
|
6
|
+
2016/12/09
|
7
|
+
|
8
|
+
allotted-time
|
9
|
+
: 20m
|
10
|
+
|
11
|
+
# About me
|
12
|
+
|
13
|
+
- ヽ(´・肉・`)ノ / @niku_name
|
14
|
+
- コンサドーレ札幌が好きです
|
15
|
+
- サッポロビームによくいます
|
16
|
+
|
17
|
+
# なるほど UNIX プロセス
|
18
|
+
|
19
|
+
![](naruhounix-cover.jpg){:relative_height='100'}
|
20
|
+
|
21
|
+
# なるほど UNIX プロセス
|
22
|
+
|
23
|
+
```
|
24
|
+
第3章 プロセスにはIDがある
|
25
|
+
第4章 プロセスには親がいる
|
26
|
+
第5章 プロセスにはファイルディスクリプタがある
|
27
|
+
第6章 プロセスにはリソースの制限がある
|
28
|
+
第7章 プロセスには環境がある
|
29
|
+
第8章 プロセスには引数がある
|
30
|
+
第9章 プロセスには名前がある
|
31
|
+
第10章 プロセスには終了コードがある
|
32
|
+
第11章 プロセスは子プロセスを作れる
|
33
|
+
第12章 孤児プロセス
|
34
|
+
第13章 プロセスは優しい
|
35
|
+
第14章 プロセスは待てる
|
36
|
+
第15章 ゾンビプロセス
|
37
|
+
第16章 プロセスはシグナルを受信できる
|
38
|
+
第17章 プロセスは通信できる
|
39
|
+
第18章 デーモンプロセス
|
40
|
+
第19章 端末プロセスを作る
|
41
|
+
```
|
42
|
+
|
43
|
+
# Erlang
|
44
|
+
|
45
|
+
- 元々は電話交換機の制御用
|
46
|
+
- 耐障害性が高い
|
47
|
+
- 並行処理が得意
|
48
|
+
|
49
|
+
# なるほど Erlang プロセス
|
50
|
+
|
51
|
+
```
|
52
|
+
Erlang プロセスには ID がある
|
53
|
+
Erlang プロセスは子プロセスを作れる
|
54
|
+
Erlang プロセスはプロセス毎に値を保持できる
|
55
|
+
Erlang プロセスはメッセージを送受信できる
|
56
|
+
Erlang プロセスは別々に動ける
|
57
|
+
Erlang プロセスは名前を束縛できる
|
58
|
+
Erlang プロセスはプロセス数を制限できる
|
59
|
+
Erlang プロセスは軽量
|
60
|
+
Erlang プロセスは exit シグナルを送る/受けとる
|
61
|
+
Erlang プロセスは繋げる
|
62
|
+
Erlang プロセスは見ておくことができる
|
63
|
+
Erlang プロセスを扱うライブラリ Erlang/OTP
|
64
|
+
```
|
65
|
+
|
66
|
+
# Erlang プロセスには ID がある
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
/Users/niku% iex
|
70
|
+
iex(1)> self()
|
71
|
+
#PID<0.80.0>
|
72
|
+
iex(2)>
|
73
|
+
```
|
74
|
+
|
75
|
+
# Erlang プロセスは子プロセスを作れる
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
iex(1)> self()
|
79
|
+
#PID<0.80.0>
|
80
|
+
iex(2)> spawn(fn ->
|
81
|
+
...(2)> IO.inspect self()
|
82
|
+
...(2)> end)
|
83
|
+
#PID<0.85.0>
|
84
|
+
#PID<0.85.0>
|
85
|
+
iex(3)>
|
86
|
+
```
|
87
|
+
|
88
|
+
# Erlang プロセスはプロセス毎に値を保持できる
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
iex(1)> Process.put(:a, "foo")
|
92
|
+
nil
|
93
|
+
iex(2)> Process.get(:a)
|
94
|
+
"foo"
|
95
|
+
iex(3)> spawn(fn ->
|
96
|
+
...(3)> IO.inspect Process.get(:a)
|
97
|
+
...(3)> end)
|
98
|
+
nil
|
99
|
+
#PID<0.86.0>
|
100
|
+
iex(4)> Process.get(:a)
|
101
|
+
"foo"
|
102
|
+
iex(5)>
|
103
|
+
```
|
104
|
+
|
105
|
+
# Erlang プロセスはメッセージを送受信できる
|
106
|
+
|
107
|
+
プロセスは,メッセージを `send` と `receive` してプロセス間のやりとりを行う.
|
108
|
+
|
109
|
+
- 送る方 `send` は非同期
|
110
|
+
- 受ける方 `receive` は同期(メッセージがくるまでブロックする)
|
111
|
+
タイムアウトできる
|
112
|
+
|
113
|
+
# Erlang プロセスはメッセージを送受信できる
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
iex(1)> child_pid = spawn(fn ->
|
117
|
+
...(1)> IO.puts "spawned"
|
118
|
+
...(1)> receive do
|
119
|
+
...(1)> x -> IO.puts "#{inspect self()} #{x}"
|
120
|
+
...(1)> end
|
121
|
+
...(1)> IO.puts "received"
|
122
|
+
...(1)> end)
|
123
|
+
spawned
|
124
|
+
#PID<0.88.0>
|
125
|
+
iex(2)> send(child_pid, "hello~")
|
126
|
+
#PID<0.88.0> hello~
|
127
|
+
received
|
128
|
+
"hello~"
|
129
|
+
iex(3)>
|
130
|
+
```
|
131
|
+
|
132
|
+
# Erlang プロセスはメッセージを送受信できる
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
child_pid = spawn(fn ->
|
136
|
+
...(1)> IO.puts "spawned"
|
137
|
+
...(1)> receive do
|
138
|
+
...(1)> x -> IO.puts "#{inspect self()} #{x}"
|
139
|
+
...(1)> after 10_000 ->
|
140
|
+
...(1)> IO.puts "Timeout"
|
141
|
+
...(1)> end
|
142
|
+
...(1)> IO.puts "received"
|
143
|
+
...(1)> end)
|
144
|
+
spawned
|
145
|
+
#PID<0.91.0>
|
146
|
+
iex(2)>
|
147
|
+
nil
|
148
|
+
iex(3)> # 10秒待つ
|
149
|
+
nil
|
150
|
+
iex(4)> Timeout
|
151
|
+
iex(4)> received
|
152
|
+
iex(4)>
|
153
|
+
```
|
154
|
+
|
155
|
+
# Erlang プロセスはメッセージを送受信できる
|
156
|
+
|
157
|
+
送る方は send で勝手におくりつけてくる
|
158
|
+
受ける方は receive を明示的に呼ばないと,メッセージを受ける体制に入らない
|
159
|
+
|
160
|
+
`x = x + 1` をマルチスレッドで動かすとおかしくなるような問題が起きない
|
161
|
+
|
162
|
+
# Erlang プロセスは別々に動ける
|
163
|
+
|
164
|
+
```ruby
|
165
|
+
# fib.exs
|
166
|
+
defmodule Fib do
|
167
|
+
def calc(n) when n == 0, do: 0
|
168
|
+
def calc(n) when n == 1, do: 1
|
169
|
+
def calc(n) when 2 <= n do
|
170
|
+
calc(n - 1) + calc(n - 2)
|
171
|
+
end
|
172
|
+
|
173
|
+
def calc_three_processes_in_parallel(n) do
|
174
|
+
me = self()
|
175
|
+
# 3並列に計算し,完了したら答えを送ってもらう
|
176
|
+
spawn(fn -> send(me, calc(n)) end)
|
177
|
+
spawn(fn -> send(me, calc(n)) end)
|
178
|
+
spawn(fn -> send(me, calc(n)) end)
|
179
|
+
do_receive([])
|
180
|
+
end
|
181
|
+
|
182
|
+
defp do_receive(result) when length(result) == 3 do
|
183
|
+
result
|
184
|
+
end
|
185
|
+
defp do_receive(result) when length(result) < 3 do
|
186
|
+
receive do
|
187
|
+
x ->
|
188
|
+
do_receive([x | result])
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
```
|
193
|
+
|
194
|
+
# Erlang プロセスは別々に動ける
|
195
|
+
|
196
|
+
```elixir
|
197
|
+
iex(1)> import_file("fib.exs")
|
198
|
+
{:module, Fib,
|
199
|
+
<<70, 79, 82, 49, 0, 0, 9, 152, 66, 69, 65, 77, 69, 120, 68, 99, 0, 0, 0, 219,
|
200
|
+
131, 104, 2, 100, 0, 14, 101, 108, 105, 120, 105, 114, 95, 100, 111, 99, 115,
|
201
|
+
95, 118, 49, 108, 0, 0, 0, 4, 104, 2, ...>>, {:do_receive, 1}}
|
202
|
+
iex(2)> {single_execution_time, answer} =
|
203
|
+
:timer.tc(Fib, :calc, [40])
|
204
|
+
{7219356, 102334155}
|
205
|
+
iex(3)> {multi_execution_time, answer} =
|
206
|
+
:timer.tc(Fib, :calc_three_processes_in_parallel, [40])
|
207
|
+
{10781720, [102334155, 102334155, 102334155]}
|
208
|
+
iex(4)> multi_execution_time / single_execution_time
|
209
|
+
1.4934462298299183
|
210
|
+
iex(5)>
|
211
|
+
```
|
212
|
+
|
213
|
+
# Erlang プロセスは名前を束縛できる
|
214
|
+
|
215
|
+
```ruby
|
216
|
+
iex(1)> child_pid = spawn(fn ->
|
217
|
+
...(1)> receive do
|
218
|
+
...(1)> x -> IO.puts "#{inspect self()}: #{x}"
|
219
|
+
...(1)> end
|
220
|
+
...(1)> end)
|
221
|
+
#PID<0.109.0>
|
222
|
+
iex(2)> Process.register(child_pid, :echo)
|
223
|
+
true
|
224
|
+
iex(3)> send(:echo, "hi")
|
225
|
+
#PID<0.109.0>: hi
|
226
|
+
"hi"
|
227
|
+
iex(4)>
|
228
|
+
```
|
229
|
+
|
230
|
+
# Erlang プロセスはプロセス数を制限できる
|
231
|
+
|
232
|
+
```ruby
|
233
|
+
iex(1)> :erlang.system_info(:process_limit)
|
234
|
+
262144
|
235
|
+
iex(2)>
|
236
|
+
```
|
237
|
+
|
238
|
+
# Erlang プロセスはプロセス数を制限できる
|
239
|
+
|
240
|
+
```ruby
|
241
|
+
/Users/niku% ELIXIR_ERL_OPTIONS="+P 1024" iex
|
242
|
+
iex(1)> :erlang.system_info(:process_limit)
|
243
|
+
1024
|
244
|
+
iex(2)> Enum.map(0..1024, fn n ->
|
245
|
+
...(2)> IO.puts Enum.count(Process.list())
|
246
|
+
...(2)> spawn(fn ->
|
247
|
+
...(2)> receive do
|
248
|
+
...(2)> x -> IO.inspect x
|
249
|
+
...(2)> end
|
250
|
+
...(2)> end)
|
251
|
+
...(2)> end)
|
252
|
+
43
|
253
|
+
44
|
254
|
+
(...snip...)
|
255
|
+
1022
|
256
|
+
1023
|
257
|
+
1024
|
258
|
+
** (SystemLimitError) a system limit has been reached
|
259
|
+
|
260
|
+
23:12:15.338 [error] Too many processes
|
261
|
+
```
|
262
|
+
|
263
|
+
# Erlang プロセスは軽量
|
264
|
+
|
265
|
+
```ruby
|
266
|
+
iex(1)> f = fn ->
|
267
|
+
...(1)> receive do
|
268
|
+
...(1)> after :infinity -> :ok
|
269
|
+
...(1)> end
|
270
|
+
...(1)> end
|
271
|
+
#Function<20.52032458/0 in :erl_eval.expr/5>
|
272
|
+
iex(2)> {_, total_bytes} = Process.info(spawn(f), :memory)
|
273
|
+
{:memory, 2720}
|
274
|
+
iex(3)> wordsize = :erlang.system_info(:wordsize)
|
275
|
+
8
|
276
|
+
iex(4)> total_bytes / wordsize
|
277
|
+
340.0
|
278
|
+
iex(5)> {_, heap_size} = Process.info(spawn(f), :heap_size)
|
279
|
+
{:heap_size, 233}
|
280
|
+
iex(6)>
|
281
|
+
```
|
282
|
+
|
283
|
+
# Erlang プロセスは軽量
|
284
|
+
|
285
|
+
- 1プロセス作るのにヒープ領域込みで最小 309 words( *2472バイト* )
|
286
|
+
- この環境では Hipe という拡張が有効になっているため 340 words になっている
|
287
|
+
|
288
|
+
# Erlang プロセスは軽量
|
289
|
+
|
290
|
+
100万プロセス動かす
|
291
|
+
|
292
|
+
# Erlang プロセスは軽量
|
293
|
+
|
294
|
+
```ruby
|
295
|
+
# chain.exs
|
296
|
+
defmodule Chain do
|
297
|
+
def create_processes(n) do
|
298
|
+
# n個目の(最後の)プロセスは親プロセスにメッセージを送る
|
299
|
+
last_pid = Enum.reduce(1..n, self(), fn (_, send_to) ->
|
300
|
+
spawn(fn ->
|
301
|
+
# メッセージを受けたら1足して次のメッセージに送る
|
302
|
+
receive do
|
303
|
+
x -> send(send_to, x + 1)
|
304
|
+
end
|
305
|
+
end)
|
306
|
+
end)
|
307
|
+
IO.puts "count: #{Enum.count(Process.list())}, memory: :#{:erlang.memory(:total)}"
|
308
|
+
send(last_pid, 0) # n個の子プロセスの最初の1個を動かす
|
309
|
+
|
310
|
+
receive do
|
311
|
+
final_answer -> "Result is #{final_answer}"
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
def run(n) do
|
316
|
+
{execution_micro_secs, final_answer} =
|
317
|
+
:timer.tc(Chain, :create_processes, [n])
|
318
|
+
seconds = execution_micro_secs / (1000 * 1000)
|
319
|
+
IO.puts "#{seconds} seconds, #{final_answer}"
|
320
|
+
end
|
321
|
+
end
|
322
|
+
```
|
323
|
+
|
324
|
+
# Erlang プロセスは軽量
|
325
|
+
|
326
|
+
```bash
|
327
|
+
/Users/niku% system_profiler SPHardwareDataType
|
328
|
+
Hardware:
|
329
|
+
|
330
|
+
Hardware Overview:
|
331
|
+
|
332
|
+
Model Name: MacBook Pro
|
333
|
+
Model Identifier: MacBookPro12,1
|
334
|
+
Processor Name: Intel Core i5
|
335
|
+
Processor Speed: 2.7 GHz
|
336
|
+
Number of Processors: 1
|
337
|
+
Total Number of Cores: 2
|
338
|
+
L2 Cache (per Core): 256 KB
|
339
|
+
L3 Cache: 3 MB
|
340
|
+
Memory: 16 GB
|
341
|
+
(...snip...)
|
342
|
+
|
343
|
+
/Users/niku% ELIXIR_ERL_OPTIONS="+P 10000000" elixir -r chain.exs -e "Chain.run(1_000_000)"
|
344
|
+
count: 1000037, memory: :2970141432
|
345
|
+
8.74099 seconds, Result is 1000000
|
346
|
+
```
|
347
|
+
|
348
|
+
# Erlang プロセスは軽量
|
349
|
+
|
350
|
+
軽量2つの利点
|
351
|
+
|
352
|
+
- かかった時間8.75秒 -> プロセス作成の速さ
|
353
|
+
- 使用メモリ3GB弱 -> 省メモリ
|
354
|
+
|
355
|
+
*カジュアルに殺したり作ったりしやすい*
|
356
|
+
|
357
|
+
# Erlang プロセスは exit シグナルを送る/受けとる
|
358
|
+
|
359
|
+
2種類の exit シグナル
|
360
|
+
|
361
|
+
1. `exit(:normal)` :: 受けとった方は何もしない
|
362
|
+
2. `exit(任意の値)` :: 受けとった方は死ぬ
|
363
|
+
|
364
|
+
# Erlang プロセスは exit シグナルを送る/受けとる
|
365
|
+
|
366
|
+
```ruby
|
367
|
+
iex(1)> other_pid = spawn(fn ->
|
368
|
+
...(1)> receive do
|
369
|
+
...(1)> x -> IO.puts x
|
370
|
+
...(1)> end
|
371
|
+
...(1)> end)
|
372
|
+
#PID<0.88.0>
|
373
|
+
iex(2)> Process.alive?(other_pid)
|
374
|
+
true
|
375
|
+
iex(3)> Process.exit(other_pid, :normal)
|
376
|
+
true
|
377
|
+
iex(4)> Process.alive?(other_pid)
|
378
|
+
true
|
379
|
+
iex(5)> Process.exit(other_pid, :omg)
|
380
|
+
true
|
381
|
+
iex(6)> Process.alive?(other_pid)
|
382
|
+
false
|
383
|
+
iex(7)>
|
384
|
+
```
|
385
|
+
|
386
|
+
# Erlang プロセスは exit シグナルを送る/受けとる
|
387
|
+
|
388
|
+
exit シグナルも特別なメッセージにすぎない
|
389
|
+
|
390
|
+
# Erlang プロセスは exit シグナルを送る/受けとる
|
391
|
+
|
392
|
+
```ruby
|
393
|
+
iex(1)> other_pid = spawn(fn ->
|
394
|
+
...(1)> Process.flag(:trap_exit, true)
|
395
|
+
...(1)> receive do
|
396
|
+
...(1)> x -> IO.inspect x
|
397
|
+
...(1)> end
|
398
|
+
...(1)> end)
|
399
|
+
#PID<0.88.0>
|
400
|
+
iex(2)>
|
401
|
+
nil
|
402
|
+
iex(3)> Process.exit(other_pid, :omg)
|
403
|
+
{:EXIT, #PID<0.81.0>, :omg}
|
404
|
+
true
|
405
|
+
iex(4)>
|
406
|
+
```
|
407
|
+
|
408
|
+
# Erlang プロセスはシグナルを送る/受けとる
|
409
|
+
|
410
|
+
exit シグナルを受けとって死ぬことに意味はあるのか?
|
411
|
+
|
412
|
+
次に挙げる特徴と組合せると便利
|
413
|
+
|
414
|
+
# Erlang プロセスは繋げる
|
415
|
+
|
416
|
+
- プロセスを繋げる(linkする)ことができる
|
417
|
+
- *繋がっていないプロセス* で何があっても *影響を受けない*
|
418
|
+
- *繋がっているプロセス* は *exitシグナルを受けとる*
|
419
|
+
|
420
|
+
# Erlang プロセスは繋げる
|
421
|
+
|
422
|
+
```ruby
|
423
|
+
iex(1)> spawn(fn ->
|
424
|
+
...(1)> Process.flag(:trap_exit, true)
|
425
|
+
...(1)>
|
426
|
+
...(1)> spawn(fn ->
|
427
|
+
...(1)> exit(:omg)
|
428
|
+
...(1)> end)
|
429
|
+
...(1)>
|
430
|
+
...(1)> receive do
|
431
|
+
...(1)> message ->
|
432
|
+
...(1)> IO.puts "An exit signal received: #{inspect message}"
|
433
|
+
...(1)> after 1000 ->
|
434
|
+
...(1)> IO.puts "timeout"
|
435
|
+
...(1)> end
|
436
|
+
...(1)> end)
|
437
|
+
#PID<0.96.0>
|
438
|
+
iex(2)>
|
439
|
+
nil
|
440
|
+
iex(3)> timeout
|
441
|
+
iex(3)>
|
442
|
+
```
|
443
|
+
|
444
|
+
# Erlang プロセスは繋げる
|
445
|
+
|
446
|
+
```ruby
|
447
|
+
iex(1)> spawn(fn ->
|
448
|
+
...(1)> Process.flag(:trap_exit, true)
|
449
|
+
...(1)>
|
450
|
+
...(1)> spawn_link(fn ->
|
451
|
+
...(1)> exit(:omg)
|
452
|
+
...(1)> end)
|
453
|
+
...(1)>
|
454
|
+
...(1)> receive do
|
455
|
+
...(1)> message ->
|
456
|
+
...(1)> IO.puts "An exit signal received: #{inspect message}"
|
457
|
+
...(1)> after 1000 ->
|
458
|
+
...(1)> IO.puts "timeout"
|
459
|
+
...(1)> end
|
460
|
+
...(1)> end)
|
461
|
+
#PID<0.96.0>
|
462
|
+
An exit signal received: {:EXIT, #PID<0.97.0>, :omg}
|
463
|
+
iex(2)>
|
464
|
+
nil
|
465
|
+
iex(3)>
|
466
|
+
```
|
467
|
+
|
468
|
+
# Erlang プロセスは繋げる
|
469
|
+
|
470
|
+
`exit` シグナルはハンドリングしないエラーがプロセスに到達した場合にも発生する
|
471
|
+
|
472
|
+
# Erlang プロセスは繋げる
|
473
|
+
|
474
|
+
```ruby
|
475
|
+
iex(1)> spawn(fn ->
|
476
|
+
...(1)> Process.flag(:trap_exit, true)
|
477
|
+
...(1)>
|
478
|
+
...(1)> spawn_link(fn ->
|
479
|
+
...(1)> 1 / 0
|
480
|
+
...(1)> end)
|
481
|
+
...(1)>
|
482
|
+
...(1)> receive do
|
483
|
+
...(1)> message ->
|
484
|
+
...(1)> IO.puts "An exit signal received: #{inspect message}"
|
485
|
+
...(1)> end
|
486
|
+
...(1)> end)
|
487
|
+
#PID<0.110.0>
|
488
|
+
iex(2)>
|
489
|
+
23:45:15.070 [error] Process #PID<0.111.0> raised an exception
|
490
|
+
** (ArithmeticError) bad argument in arithmetic expression
|
491
|
+
:erlang./(1, 0)
|
492
|
+
An exit signal received: {:EXIT, #PID<0.111.0>, {:badarith, [{:erlang, :/, [1, 0], []}]}}
|
493
|
+
iex(2)>
|
494
|
+
```
|
495
|
+
|
496
|
+
# Erlang プロセスは繋げる
|
497
|
+
|
498
|
+
[再掲] exit シグナルを受けとって死ぬことに意味はあるのか?
|
499
|
+
|
500
|
+
# Erlang プロセスは繋げる
|
501
|
+
|
502
|
+
> もしエラーのあるプロセスがクラッシュしたけれど、それに依存しているプロセスが動き続けているとしたら、それら依存プロセスすべては依存先がなくなったことに対処しなければならなくなります。
|
503
|
+
|
504
|
+
すごいErlangゆかいに学ぼう!第 12 章 - エラーとプロセス
|
505
|
+
|
506
|
+
# Erlang プロセスは繋げる
|
507
|
+
|
508
|
+
- 意味のあるグループで複数のプロセスを繋げる :: *プロセス管理対象数の抑制*
|
509
|
+
- 1つのプロセスが死んだらグループ全てのプロセスが死ぬ :: *グループの中途半端な状態の抑制*
|
510
|
+
- 死んだことがすぐ検知できる :: *すぐ新しいプロセスを作ることができる*
|
511
|
+
|
512
|
+
# Erlang プロセスは繋げる
|
513
|
+
|
514
|
+
- 静的型付き言語はランタイムエラーを起こさないことを目指すことで(100%の)安定動作を目指せる
|
515
|
+
- ErlangVM はエラーになったときに,検知/再開を素早く行うことを目指すことで(99.9...%の)安定動作を目指せる
|
516
|
+
|
517
|
+
*ソースなし(私見)*
|
518
|
+
|
519
|
+
# Erlang プロセスは見ておくことができる
|
520
|
+
|
521
|
+
- プロセスを見ておく(monitor)できる
|
522
|
+
- 見るプロセス,見られるプロセスという立場が存在する
|
523
|
+
- 2 つのプロセス間で複数のモニターが持てる(スタックでき,それぞれに識別できる)
|
524
|
+
|
525
|
+
# Erlang プロセスは見ておくことができる
|
526
|
+
|
527
|
+
- 見る方が死んでも,見られる方には関係ない
|
528
|
+
- モニターを複数作れる
|
529
|
+
|
530
|
+
ライブラリのような,相互に強固に結びついていないプロセスが,他のプロセスを監視するのに向いている
|
531
|
+
|
532
|
+
# Erlang プロセスは見ておくことができる
|
533
|
+
|
534
|
+
```ruby
|
535
|
+
iex(1)> spawn(fn ->
|
536
|
+
...(1)> spawn_monitor(fn ->
|
537
|
+
...(1)> exit(:omg)
|
538
|
+
...(1)> end)
|
539
|
+
...(1)>
|
540
|
+
...(1)> receive do
|
541
|
+
...(1)> message ->
|
542
|
+
...(1)> IO.puts "An exit signal received: #{inspect message}"
|
543
|
+
...(1)> end
|
544
|
+
...(1)> end)
|
545
|
+
#PID<0.92.0>
|
546
|
+
An exit signal received: {:DOWN, #Reference<0.0.4.260>, :process, #PID<0.93.0>, :omg}
|
547
|
+
iex(2)>
|
548
|
+
nil
|
549
|
+
iex(3)>
|
550
|
+
```
|
551
|
+
|
552
|
+
# Erlang プロセスを扱うライブラリ Erlang/OTP
|
553
|
+
|
554
|
+
- 本体に同梱されている
|
555
|
+
- プロセス間のインタラクションをいい感じに
|
556
|
+
|
557
|
+
# Erlang プロセスを扱うライブラリ Erlang/OTP
|
558
|
+
|
559
|
+
```ruby
|
560
|
+
# stack.exs
|
561
|
+
defmodule Stack do
|
562
|
+
use GenServer # OTPに含まれるライブラリ
|
563
|
+
|
564
|
+
def start_link(state, opts \\ []) do
|
565
|
+
GenServer.start_link(__MODULE__, state, opts)
|
566
|
+
end
|
567
|
+
|
568
|
+
# 初期化
|
569
|
+
def init(state) do
|
570
|
+
{:ok, state}
|
571
|
+
end
|
572
|
+
|
573
|
+
# 同期呼び出し
|
574
|
+
def handle_call(:pop, _from, [h | t]) do
|
575
|
+
{:reply, h, t}
|
576
|
+
end
|
577
|
+
|
578
|
+
# 非同期呼び出し
|
579
|
+
def handle_cast({:push, item}, state) do
|
580
|
+
{:noreply, [item | state]}
|
581
|
+
end
|
582
|
+
end
|
583
|
+
```
|
584
|
+
|
585
|
+
# Erlang プロセスを扱うライブラリ Erlang/OTP
|
586
|
+
|
587
|
+
```elixir
|
588
|
+
iex(1)> import_file("stack.exs")
|
589
|
+
{:module, Stack,
|
590
|
+
<<70, 79, 82, 49, 0, 0, 12, 104, 66, 69, 65, 77, 69, 120, 68, 99, 0, 0, 2, 144,
|
591
|
+
131, 104, 2, 100, 0, 14, 101, 108, 105, 120, 105, 114, 95, 100, 111, 99, 115,
|
592
|
+
95, 118, 49, 108, 0, 0, 0, 4, 104, 2, ...>>, {:handle_cast, 2}}
|
593
|
+
iex(2)> import Supervisor.Spec
|
594
|
+
Supervisor.Spec
|
595
|
+
iex(3)> children = [
|
596
|
+
...(3)> worker(Stack, [[:hello], [name: MyStack]])
|
597
|
+
...(3)> ]
|
598
|
+
[{Stack, {Stack, :start_link, [[:hello], [name: MyStack]]}, :permanent, 5000,
|
599
|
+
:worker, [Stack]}]
|
600
|
+
iex(4)> {:ok, pid} = Supervisor.start_link(children, strategy: :one_for_one)
|
601
|
+
{:ok, #PID<0.91.0>}
|
602
|
+
```
|
603
|
+
|
604
|
+
# Erlang プロセスを扱うライブラリ Erlang/OTP
|
605
|
+
|
606
|
+
```ruby
|
607
|
+
iex(5)> GenServer.call(MyStack, :pop)
|
608
|
+
:hello
|
609
|
+
iex(6)> GenServer.cast(MyStack, {:push, :world})
|
610
|
+
:ok
|
611
|
+
iex(7)> GenServer.call(MyStack, :pop)
|
612
|
+
:world
|
613
|
+
iex(8)> GenServer.call(MyStack, :pop)
|
614
|
+
(...snip...)
|
615
|
+
17:08:37.217 [error] GenServer MyStack terminating
|
616
|
+
** (FunctionClauseError) no function clause matching in Stack.handle_call/3
|
617
|
+
iex:15: Stack.handle_call(:pop, {#PID<0.80.0>, #Reference<0.0.4.299>}, [])
|
618
|
+
(stdlib) gen_server.erl:615: :gen_server.try_handle_call/4
|
619
|
+
(stdlib) gen_server.erl:647: :gen_server.handle_msg/5
|
620
|
+
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
|
621
|
+
Last message: :pop
|
622
|
+
State: []
|
623
|
+
(elixir) lib/gen_server.ex:737: GenServer.call/3
|
624
|
+
iex(8)> GenServer.call(MyStack, :pop)
|
625
|
+
:hello
|
626
|
+
iex(9)>
|
627
|
+
```
|
628
|
+
|
629
|
+
# 今日話したこと
|
630
|
+
|
631
|
+
- ErlangVM のプロセス軽量
|
632
|
+
- ErlangVM のプロセス間のやりとり,エラー処理
|
633
|
+
- メッセージパッシング
|
634
|
+
- リンク
|
635
|
+
- モニター
|
636
|
+
- 使いやすくしたライブラリ OTP
|
637
|
+
|
638
|
+
# まとめ
|
639
|
+
|
640
|
+
- プロセス同士のインタラクションで耐障害性を担保
|
641
|
+
- 土台(プロセス)から上については意識する機会が多い
|
642
|
+
- 土台(プロセス)とか,土台(プロセス)同士のインタラクションとか意識して知ると便利かもよ
|
643
|
+
|
644
|
+
# まとめ
|
645
|
+
|
646
|
+
だいたい毎週木曜日19:00から ErlangVM やそうでないことについてわいわいやる *オンライン参加もできる* サッポロビーム
|
647
|
+
|
648
|
+
# 今日話したこと
|
649
|
+
|
650
|
+
- ErlangVM のプロセス軽量
|
651
|
+
- ErlangVM のプロセス間のやりとり,エラー処理
|
652
|
+
- メッセージパッシング
|
653
|
+
- リンク
|
654
|
+
- モニター
|
655
|
+
- 使いやすくしたライブラリ OTP
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rabbit-slide-niku-yapc-hokkaido-2016-eve-naruhodo-erlang-process
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- niku
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-12-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rabbit
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.0.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.0.2
|
27
|
+
description: |-
|
28
|
+
[YAPC::Hokkaido 2016 SAPPORO 前夜祭](http://passmarket.yahoo.co.jp/event/show/detail/0170cmyfxi8j.html) での
|
29
|
+
「なるほどErlangプロセス」発表資料
|
30
|
+
email:
|
31
|
+
- niku@niku.name
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- ".rabbit"
|
37
|
+
- README.md
|
38
|
+
- Rakefile
|
39
|
+
- config.yaml
|
40
|
+
- naruhounix-cover.jpg
|
41
|
+
- pdf/yapc-hokkaido-2016-eve-naruhodo-erlang-process-yapc-hokkaido-2016-eve-naruhodo-erlang-process.pdf
|
42
|
+
- yapc-hokkaido-2016-eve-naruhodo-erlang-process.md
|
43
|
+
homepage: http://slide.rabbit-shocker.org/authors/niku/yapc-hokkaido-2016-eve-naruhodo-erlang-process/
|
44
|
+
licenses: []
|
45
|
+
metadata: {}
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
requirements: []
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 2.5.1
|
63
|
+
signing_key:
|
64
|
+
specification_version: 4
|
65
|
+
summary: なるほど Erlang プロセス
|
66
|
+
test_files: []
|