1
1
# Actor model
2
2
3
- - Light-weighted.
3
+ - Light-weighted running on thread-pool .
4
4
- Inspired by Akka and Erlang.
5
5
- Modular.
6
6
7
- Actors are sharing a thread-pool by default which makes them very cheap to create and discard.
8
- Thousands of actors can be created, allowing you to break the program into small maintainable pieces,
9
- without violating the single responsibility principle.
7
+ This Actor model implementation makes makes actors very cheap to create and discard.
8
+ Thousands of actors can be created, allowing you to break the program into smaller
9
+ maintainable pieces, without violating the single responsibility principle.
10
10
11
11
## What is an actor model?
12
12
13
- [ Wiki] ( http://en.wikipedia.org/wiki/Actor_model ) says:
14
- The actor model in computer science is a mathematical model of concurrent computation
15
- that treats _ actors_ as the universal primitives of concurrent digital computation:
13
+ Actor-based concurrency is all the rage in some circles. Originally described in 1973, the actor model is a paradigm
14
+ for creating asynchronous, concurrent objects that is becoming increasingly popular. Much has changed since actors
15
+ were first written about four decades ago, which has led to a serious fragmentation within the actor community.
16
+ There is * no* universally accepted, strict definition of "actor" and actor implementations differ widely between
17
+ languages and libraries.
18
+
19
+ [ Wiki] ( http://en.wikipedia.org/wiki/Actor_model ) definition is pretty good:
20
+ _ The actor model in computer science is a mathematical model of concurrent computation
21
+ that treats ** actors** as the universal primitives of concurrent digital computation:
16
22
in response to a message that it receives, an actor can make local decisions,
17
23
create more actors, send more messages, and determine how to respond to the next
18
- message received.
24
+ message received._
19
25
20
26
## Why?
21
27
22
- Concurrency is hard this is one of many ways how to simplify the problem.
23
- It is simpler to reason about actors than about locks (and all their possible states).
28
+ Concurrency is hard to get right, actors are one of many ways how to simplify the problem.
24
29
25
- ## How to use it
30
+ ## Quick example
26
31
27
32
{include:file: doc /actor/quick.out.rb}
28
33
29
- ## Messaging
34
+ ## Spawning actors
35
+
36
+ - {Concurrent::Actor.spawn} and {Concurrent::Actor.spawn!}
37
+ - {Concurrent::Actor::AbstractContext.spawn} and {Concurrent::Actor::AbstractContext.spawn!}
38
+
39
+ ## Sending messages
40
+
41
+ - {Concurrent::Actor::Reference#tell}
42
+ {include:Concurrent::Actor::Reference#tell}
43
+ - {Concurrent::Actor::Reference#ask}
44
+ {include:Concurrent::Actor::Reference#ask}
45
+ - {Concurrent::Actor::Reference#ask!}
46
+ {include:Concurrent::Actor::Reference#ask!}
30
47
31
48
Messages are processed in same order as they are sent by a sender. It may interleaved with
32
- messages form other senders though. There is also a contract in actor model that
33
- messages sent between actors should be immutable. Gems like
49
+ messages from other senders though.
50
+
51
+ ### Immutability
52
+
53
+ Messages sent between actors should be ** immutable** . Gems like
34
54
35
55
- [ Algebrick] ( https://github.com/pitr-ch/algebrick ) - Typed struct on steroids based on
36
56
algebraic types and pattern matching
37
57
- [ Hamster] ( https://github.com/hamstergem/hamster ) - Efficient, Immutable, Thread-Safe
38
58
Collection classes for Ruby
39
59
40
- are very useful .
60
+ are very helpful .
41
61
42
- ### Dead letter routing
62
+ {include:file : doc /actor/messaging.out.rb}
43
63
44
- see {AbstractContext#dead_letter_routing} description:
64
+ ## Actor definition
45
65
46
- > {include:Actor::AbstractContext#dead_letter_routing}
66
+ {include:Concurrent::Actor::AbstractContext}
67
+
68
+ ## Reference
69
+
70
+ {include:Actor::Reference}
71
+
72
+ ## Garbage collection
73
+
74
+ Spawned actor cannot be garbage-collected until it's terminated. There is a reference held in the parent actor.
75
+
76
+ ## Parent-child relationship, name, and path
77
+
78
+ - {Core#name}
79
+ {include:Actor::Core#name}
80
+ - {Core#path}
81
+ {include:Actor::Core#path}
82
+ - {Core#parent}
83
+ {include:Actor::Core#parent}
47
84
48
- ## Architecture
85
+ ## Behaviour
86
+
87
+ {include:Actor::Behaviour}
88
+
89
+ ## IO cooperation
49
90
50
91
Actors are running on shared thread poll which allows user to create many actors cheaply.
51
92
Downside is that these actors cannot be directly used to do IO or other blocking operations.
@@ -56,19 +97,31 @@ Blocking operations could starve the `default_task_pool`. However there are two
56
97
- Create an actor using ` global_operation_pool ` instead of ` global_task_pool ` , e.g.
57
98
` AnIOActor.spawn name: :blocking, executor: Concurrent.configuration.global_operation_pool ` .
58
99
59
- Each actor is composed from 4 parts:
100
+ ## Dead letter routing
60
101
61
- ### {Reference}
62
- {include:Actor::Reference}
102
+ see {AbstractContext#dead_letter_routing} description:
63
103
64
- ### {Core}
65
- {include:Actor::Core}
104
+ > {include:Actor::AbstractContext#dead_letter_routing}
66
105
67
- ### {AbstractContext}
68
- {include:Actor::AbstractContext}
106
+ ## FAQ
69
107
70
- ### {Behaviour}
71
- {include:Actor::Behaviour}
108
+ ### What happens if I try to supervise using a normal Context?
109
+
110
+ Alleged supervisor will receive errors from its supervised actors. They'll have to be handled manually.
111
+
112
+ ### How to change supervision strategy?
113
+
114
+ Use option ` behaviour_definition: Behaviour.restarting_behaviour_definition(:resume!) ` or
115
+ ` behaviour_definition: Behaviour.restarting_behaviour_definition(:reset!, :one_for_all) `
116
+
117
+ ### How to change behaviors?
118
+
119
+ Any existing behavior can be subclassed
120
+
121
+ ### How to implement custom restarting?
122
+
123
+ By subclassing {Behaviour::Pausing} and overriding {Behaviour::Pausing#restart!}. Implementing
124
+ {AbstractContext#on_event} could be also considered.
72
125
73
126
## Speed
74
127
@@ -85,49 +138,49 @@ Benchmark legend:
85
138
86
139
### JRUBY
87
140
88
- Rehearsal --------------------------------------------------------
89
- 50000 2 concurrent 24.110000 0.800000 24.910000 ( 7.728000 )
90
- 50000 2 celluloid 28.510000 4.780000 33.290000 ( 14.782000 )
91
- 50000 500 concurrent 13.700000 0.280000 13.980000 ( 4.307000 )
92
- 50000 500 celluloid 14.520000 11.740000 26.260000 ( 12.258000 )
93
- 50000 1000 concurrent 10.890000 0.220000 11.110000 ( 3.760000 )
94
- 50000 1000 celluloid 15.600000 21.690000 37.290000 ( 18.512000 )
95
- 50000 1500 concurrent 10.580000 0.270000 10.850000 ( 3.646000 )
96
- 50000 1500 celluloid 14.490000 29.790000 44.280000 ( 26.043000 )
97
- --------------------------------------------- total: 201.970000sec
141
+ Rehearsal ---------------------------------------------------------
142
+ 50000 2 concurrent 26.140000 0.610000 26.750000 ( 7.761000 )
143
+ 50000 2 celluloid 41.440000 5.270000 46.710000 ( 17.535000 )
144
+ 50000 500 concurrent 11.340000 0.180000 11.520000 ( 3.498000 )
145
+ 50000 500 celluloid 19.310000 10.680000 29.990000 ( 14.619000 )
146
+ 50000 1000 concurrent 10.640000 0.180000 10.820000 ( 3.563000 )
147
+ 50000 1000 celluloid 17.840000 19.850000 37.690000 ( 18.892000 )
148
+ 50000 1500 concurrent 14.120000 0.290000 14.410000 ( 4.618000 )
149
+ 50000 1500 celluloid 19.060000 28.920000 47.980000 ( 25.185000 )
150
+ ---------------------------------------------- total: 225.870000sec
98
151
99
- mes. act. impl. user system total real
100
- 50000 2 concurrent 9.820000 0.510000 10.330000 ( 5.735000 )
101
- 50000 2 celluloid 10.390000 4.030000 14.420000 ( 7.494000 )
102
- 50000 500 concurrent 9.880000 0.200000 10.080000 ( 3.310000 )
103
- 50000 500 celluloid 12.430000 11.310000 23.740000 ( 11.727000 )
104
- 50000 1000 concurrent 10.590000 0.190000 10.780000 ( 4.029000 )
105
- 50000 1000 celluloid 14.950000 23.260000 38.210000 ( 20.841000 )
106
- 50000 1500 concurrent 10.710000 0.250000 10.960000 ( 3.892000 )
107
- 50000 1500 celluloid 13.280000 30.030000 43.310000 ( 24.620000 ) (1)
152
+ mes. act. impl. user system total real
153
+ 50000 2 concurrent 7.320000 0.530000 7.850000 ( 3.637000 )
154
+ 50000 2 celluloid 13.780000 4.730000 18.510000 ( 10.756000 )
155
+ 50000 500 concurrent 9.270000 0.140000 9.410000 ( 3.020000 )
156
+ 50000 500 celluloid 16.540000 10.920000 27.460000 ( 14.308000 )
157
+ 50000 1000 concurrent 9.970000 0.160000 10.130000 ( 3.445000 )
158
+ 50000 1000 celluloid 15.930000 20.840000 36.770000 ( 18.272000 )
159
+ 50000 1500 concurrent 11.580000 0.240000 11.820000 ( 3.723000 )
160
+ 50000 1500 celluloid 19.440000 29.060000 48.500000 ( 25.227000 ) (1)
108
161
109
162
### MRI 2.1.0
110
163
111
- Rehearsal --------------------------------------------------------
112
- 50000 2 concurrent 4.640000 0.080000 4.720000 ( 4.852390 )
113
- 50000 2 celluloid 6.110000 2.300000 8.410000 ( 7.898069 )
114
- 50000 500 concurrent 6.260000 2.210000 8.470000 ( 7.400573 )
115
- 50000 500 celluloid 10.250000 4.930000 15.180000 ( 14.174329 )
116
- 50000 1000 concurrent 6.300000 1.860000 8.160000 ( 7.303162 )
117
- 50000 1000 celluloid 12.300000 7.090000 19.390000 ( 17.962621 )
118
- 50000 1500 concurrent 7.410000 2.610000 10.020000 ( 8.887396 )
119
- 50000 1500 celluloid 14.850000 10.690000 25.540000 ( 24.489796 )
120
- ---------------------------------------------- total: 99.890000sec
164
+ Rehearsal ---------------------------------------------------------
165
+ 50000 2 concurrent 4.180000 0.080000 4.260000 ( 4.269435 )
166
+ 50000 2 celluloid 7.740000 3.100000 10.840000 ( 10.043875 )
167
+ 50000 500 concurrent 5.900000 1.310000 7.210000 ( 6.565067 )
168
+ 50000 500 celluloid 12.820000 5.810000 18.630000 ( 17.320765 )
169
+ 50000 1000 concurrent 6.080000 1.640000 7.720000 ( 6.931294 )
170
+ 50000 1000 celluloid 17.130000 8.320000 25.450000 ( 23.786146 )
171
+ 50000 1500 concurrent 6.940000 2.030000 8.970000 ( 7.927330 )
172
+ 50000 1500 celluloid 20.980000 12.040000 33.020000 ( 30.849578 )
173
+ ---------------------------------------------- total: 116.100000sec
121
174
122
- mes. act. impl. user system total real
123
- 50000 2 concurrent 4.190000 0.070000 4.260000 ( 4.306386 )
124
- 50000 2 celluloid 6.490000 2.210000 8.700000 ( 8.280051 )
125
- 50000 500 concurrent 7.060000 2.520000 9.580000 ( 8.518707 )
126
- 50000 500 celluloid 10.550000 4.980000 15.530000 ( 14.699962 )
127
- 50000 1000 concurrent 6.440000 1.870000 8.310000 ( 7.571059 )
128
- 50000 1000 celluloid 12.340000 7.510000 19.850000 ( 18.793591 )
129
- 50000 1500 concurrent 6.720000 2.160000 8.880000 ( 7.929630 )
130
- 50000 1500 celluloid 14.140000 10.130000 24.270000 ( 22.775288 ) (1)
175
+ mes. act. impl. user system total real
176
+ 50000 2 concurrent 3.730000 0.100000 3.830000 ( 3.822688 )
177
+ 50000 2 celluloid 7.900000 2.910000 10.810000 ( 9.924014 )
178
+ 50000 500 concurrent 5.420000 1.230000 6.650000 ( 6.025579 )
179
+ 50000 500 celluloid 12.720000 5.540000 18.260000 ( 16.889517 )
180
+ 50000 1000 concurrent 5.420000 0.910000 6.330000 ( 5.896689 )
181
+ 50000 1000 celluloid 16.090000 8.040000 24.130000 ( 22.347102 )
182
+ 50000 1500 concurrent 5.580000 0.760000 6.340000 ( 6.038535 )
183
+ 50000 1500 celluloid 20.000000 11.680000 31.680000 ( 29.590774 ) (1)
131
184
132
185
* Note (1):* Celluloid is using thread per actor so this bench is creating about 1500
133
186
native threads. Actor is using constant number of threads.
0 commit comments