polyphony 0.45.0 → 0.46.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +2 -0
- data/.gitmodules +0 -0
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +38 -0
- data/Gemfile.lock +11 -3
- data/README.md +3 -3
- data/Rakefile +1 -1
- data/TODO.md +10 -18
- data/examples/adapters/redis_client.rb +3 -1
- data/examples/adapters/redis_pubsub_perf.rb +11 -8
- data/examples/adapters/sequel_mysql.rb +1 -1
- data/examples/adapters/sequel_pg.rb +24 -0
- data/examples/core/{02-awaiting-fibers.rb → await.rb} +0 -0
- data/examples/core/{xx-channels.rb → channels.rb} +0 -0
- data/examples/core/deferring-an-operation.rb +16 -0
- data/examples/core/{xx-erlang-style-genserver.rb → erlang-style-genserver.rb} +16 -9
- data/examples/core/{xx-forking.rb → forking.rb} +1 -1
- data/examples/core/handling-signals.rb +11 -0
- data/examples/core/{03-interrupting.rb → interrupt.rb} +0 -0
- data/examples/core/{xx-pingpong.rb → pingpong.rb} +7 -5
- data/examples/core/{xx-recurrent-timer.rb → recurrent-timer.rb} +1 -1
- data/examples/core/{xx-resource_delegate.rb → resource_delegate.rb} +3 -4
- data/examples/core/{01-spinning-up-fibers.rb → spin.rb} +1 -1
- data/examples/core/{xx-spin_error_backtrace.rb → spin_error_backtrace.rb} +1 -1
- data/examples/core/{xx-supervise-process.rb → supervise-process.rb} +8 -5
- data/examples/core/supervisor.rb +20 -0
- data/examples/core/{xx-thread-sleep.rb → thread-sleep.rb} +0 -0
- data/examples/core/{xx-thread_pool.rb → thread_pool.rb} +0 -0
- data/examples/core/{xx-throttling.rb → throttling.rb} +0 -0
- data/examples/core/{xx-timeout.rb → timeout.rb} +0 -0
- data/examples/core/{xx-using-a-mutex.rb → using-a-mutex.rb} +0 -0
- data/examples/core/{xx-worker-thread.rb → worker-thread.rb} +2 -2
- data/examples/io/{xx-backticks.rb → backticks.rb} +0 -0
- data/examples/io/{xx-echo_client.rb → echo_client.rb} +1 -1
- data/examples/io/{xx-echo_client_from_stdin.rb → echo_client_from_stdin.rb} +2 -2
- data/examples/io/{xx-echo_pipe.rb → echo_pipe.rb} +1 -1
- data/examples/io/{xx-echo_server.rb → echo_server.rb} +0 -0
- data/examples/io/{xx-echo_server_with_timeout.rb → echo_server_with_timeout.rb} +1 -1
- data/examples/io/{xx-echo_stdin.rb → echo_stdin.rb} +0 -0
- data/examples/io/{xx-happy-eyeballs.rb → happy-eyeballs.rb} +0 -0
- data/examples/io/{xx-httparty.rb → httparty.rb} +4 -13
- data/examples/io/{xx-irb.rb → irb.rb} +0 -0
- data/examples/io/{xx-net-http.rb → net-http.rb} +0 -0
- data/examples/io/{xx-open.rb → open.rb} +0 -0
- data/examples/io/{xx-pry.rb → pry.rb} +0 -0
- data/examples/io/{xx-rack_server.rb → rack_server.rb} +0 -0
- data/examples/io/raw.rb +14 -0
- data/examples/io/reline.rb +18 -0
- data/examples/io/{xx-system.rb → system.rb} +1 -1
- data/examples/io/{xx-tcpserver.rb → tcpserver.rb} +0 -0
- data/examples/io/{xx-tcpsocket.rb → tcpsocket.rb} +0 -0
- data/examples/io/tunnel.rb +6 -1
- data/examples/io/{xx-zip.rb → zip.rb} +0 -0
- data/examples/performance/fiber_transfer.rb +2 -1
- data/examples/performance/fs_read.rb +5 -6
- data/examples/performance/multi_snooze.rb +0 -1
- data/examples/{io/xx-switch.rb → performance/switch.rb} +2 -1
- data/examples/performance/thread-vs-fiber/{xx-httparty_multi.rb → httparty_multi.rb} +3 -4
- data/examples/performance/thread-vs-fiber/{xx-httparty_threaded.rb → httparty_threaded.rb} +0 -0
- data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +1 -1
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -2
- data/examples/performance/thread-vs-fiber/threaded_server.rb +1 -5
- data/examples/performance/thread_pool_perf.rb +6 -7
- data/ext/liburing/liburing.h +585 -0
- data/ext/liburing/liburing/README.md +4 -0
- data/ext/liburing/liburing/barrier.h +73 -0
- data/ext/liburing/liburing/compat.h +15 -0
- data/ext/liburing/liburing/io_uring.h +343 -0
- data/ext/liburing/queue.c +333 -0
- data/ext/liburing/register.c +187 -0
- data/ext/liburing/setup.c +210 -0
- data/ext/liburing/syscall.c +54 -0
- data/ext/liburing/syscall.h +18 -0
- data/ext/polyphony/backend.h +1 -16
- data/ext/polyphony/backend_common.h +109 -0
- data/ext/polyphony/backend_io_uring.c +884 -0
- data/ext/polyphony/backend_io_uring_context.c +73 -0
- data/ext/polyphony/backend_io_uring_context.h +52 -0
- data/ext/polyphony/{libev_backend.c → backend_libev.c} +255 -345
- data/ext/polyphony/event.c +1 -1
- data/ext/polyphony/extconf.rb +31 -13
- data/ext/polyphony/fiber.c +111 -27
- data/ext/polyphony/libev.c +4 -0
- data/ext/polyphony/libev.h +8 -2
- data/ext/polyphony/liburing.c +8 -0
- data/ext/polyphony/playground.c +51 -0
- data/ext/polyphony/polyphony.c +6 -8
- data/ext/polyphony/polyphony.h +29 -25
- data/ext/polyphony/polyphony_ext.c +13 -6
- data/ext/polyphony/queue.c +3 -4
- data/ext/polyphony/ring_buffer.c +0 -1
- data/ext/polyphony/runqueue.c +102 -0
- data/ext/polyphony/runqueue_ring_buffer.c +85 -0
- data/ext/polyphony/runqueue_ring_buffer.h +31 -0
- data/ext/polyphony/thread.c +45 -92
- data/lib/polyphony.rb +2 -2
- data/lib/polyphony/adapters/fs.rb +1 -1
- data/lib/polyphony/adapters/process.rb +0 -3
- data/lib/polyphony/adapters/redis.rb +1 -1
- data/lib/polyphony/adapters/trace.rb +2 -2
- data/lib/polyphony/core/global_api.rb +9 -12
- data/lib/polyphony/core/sync.rb +6 -2
- data/lib/polyphony/extensions/core.rb +6 -24
- data/lib/polyphony/extensions/debug.rb +13 -0
- data/lib/polyphony/extensions/fiber.rb +21 -44
- data/lib/polyphony/extensions/io.rb +55 -10
- data/lib/polyphony/extensions/socket.rb +70 -12
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +3 -2
- data/test/helper.rb +36 -4
- data/test/io_uring_test.rb +55 -0
- data/test/stress.rb +5 -2
- data/test/test_backend.rb +4 -6
- data/test/test_ext.rb +1 -2
- data/test/test_fiber.rb +31 -24
- data/test/test_global_api.rb +58 -31
- data/test/test_io.rb +58 -0
- data/test/test_signal.rb +11 -8
- data/test/test_socket.rb +17 -0
- data/test/test_sync.rb +21 -0
- data/test/test_throttler.rb +3 -6
- data/test/test_trace.rb +7 -5
- metadata +86 -76
- data/examples/adapters/concurrent-ruby.rb +0 -9
- data/examples/core/04-handling-signals.rb +0 -19
- data/examples/core/xx-at_exit.rb +0 -29
- data/examples/core/xx-backend.rb +0 -102
- data/examples/core/xx-caller.rb +0 -12
- data/examples/core/xx-daemon.rb +0 -14
- data/examples/core/xx-deadlock.rb +0 -8
- data/examples/core/xx-deferring-an-operation.rb +0 -14
- data/examples/core/xx-exception-backtrace.rb +0 -40
- data/examples/core/xx-fork-cleanup.rb +0 -22
- data/examples/core/xx-fork-spin.rb +0 -42
- data/examples/core/xx-fork-terminate.rb +0 -27
- data/examples/core/xx-move_on.rb +0 -23
- data/examples/core/xx-queue-async.rb +0 -120
- data/examples/core/xx-readpartial.rb +0 -18
- data/examples/core/xx-signals.rb +0 -16
- data/examples/core/xx-sleep-forever.rb +0 -9
- data/examples/core/xx-sleeping.rb +0 -25
- data/examples/core/xx-snooze-starve.rb +0 -16
- data/examples/core/xx-spin-fork.rb +0 -49
- data/examples/core/xx-state-machine.rb +0 -51
- data/examples/core/xx-stop.rb +0 -20
- data/examples/core/xx-supervisors.rb +0 -21
- data/examples/core/xx-thread-selector-sleep.rb +0 -51
- data/examples/core/xx-thread-selector-snooze.rb +0 -46
- data/examples/core/xx-thread-snooze.rb +0 -34
- data/examples/core/xx-timer-gc.rb +0 -17
- data/examples/core/xx-trace.rb +0 -79
- data/examples/performance/xx-array.rb +0 -11
- data/examples/performance/xx-fiber-switch.rb +0 -9
- data/examples/performance/xx-snooze.rb +0 -15
- data/examples/xx-spin.rb +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 890abc2b84ed305f591c697764ea16255059aeb3cd4ddd23195b81f78f5f6daf
|
4
|
+
data.tar.gz: a02442318f82682ba1fa3a87e2b4e7ad8ae06d365a7d4a4b5c45689b2e55472f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 506a2fdbdee9e6c5bb94b976489537792941326080441f3d93924cd9657db5188b29e4ced6e1c8a6f8db06ae211da0522b3ac042e45365be1af2e68f8b157b0e
|
7
|
+
data.tar.gz: cbc0e333731e035c2094abfa72d425e649c210a8c9d3aec467446f615315cfc6e1f6de664321099ccdf93ddd6e1bb0ba484b2b8b53922725b2df8483aedefeab
|
data/.github/workflows/test.yml
CHANGED
data/.gitmodules
ADDED
File without changes
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,41 @@
|
|
1
|
+
## 0.46.0
|
2
|
+
|
3
|
+
* Implement [io_uring backend](https://github.com/digital-fabric/polyphony/pull/44)
|
4
|
+
|
5
|
+
## 0.45.5
|
6
|
+
|
7
|
+
* Fix compilation error (#43)
|
8
|
+
* Add support for resetting move_on_after, cancel_after timeouts
|
9
|
+
* Optimize anti-event starvation polling
|
10
|
+
* Implement optimized runqueue for better performance
|
11
|
+
* Schedule parent with priority on uncaught exception
|
12
|
+
* Fix race condition in `Mutex#synchronize` (#41)
|
13
|
+
|
14
|
+
## 0.45.4
|
15
|
+
|
16
|
+
* Improve signal trapping mechanism
|
17
|
+
|
18
|
+
## 0.45.3
|
19
|
+
|
20
|
+
* Don't swallow error in `Process#kill_and_await`
|
21
|
+
* Add `Fiber#mailbox` attribute reader
|
22
|
+
* Fix bug in `Fiber.await`
|
23
|
+
* Implement `IO#getc`, `IO#getbyte`
|
24
|
+
|
25
|
+
## 0.45.2
|
26
|
+
|
27
|
+
* Rewrite `Fiber#<<`, `Fiber#await`, `Fiber#receive` in C
|
28
|
+
|
29
|
+
## 0.45.1
|
30
|
+
|
31
|
+
* Fix Net::HTTP compatibility
|
32
|
+
* Fix fs adapter
|
33
|
+
* Improve performance of IO#puts
|
34
|
+
* Mutex#synchronize
|
35
|
+
* Fix Socket#connect
|
36
|
+
* Cleanup code
|
37
|
+
* Improve support for Ruby 3 keyword args
|
38
|
+
|
1
39
|
## 0.45.0
|
2
40
|
|
3
41
|
* Cleanup code
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
polyphony (0.
|
4
|
+
polyphony (0.46.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -23,6 +23,9 @@ GEM
|
|
23
23
|
forwardable-extended (2.6.0)
|
24
24
|
hiredis (0.6.3)
|
25
25
|
http_parser.rb (0.6.0)
|
26
|
+
httparty (0.17.1)
|
27
|
+
mime-types (~> 3.0)
|
28
|
+
multi_xml (>= 0.5.2)
|
26
29
|
i18n (0.9.5)
|
27
30
|
concurrent-ruby (~> 1.0)
|
28
31
|
jekyll (3.8.6)
|
@@ -60,12 +63,16 @@ GEM
|
|
60
63
|
rb-inotify (~> 0.9, >= 0.9.10)
|
61
64
|
mercenary (0.3.6)
|
62
65
|
method_source (1.0.0)
|
66
|
+
mime-types (3.3.1)
|
67
|
+
mime-types-data (~> 3.2015)
|
68
|
+
mime-types-data (3.2020.0512)
|
63
69
|
minitest (5.13.0)
|
64
70
|
minitest-reporters (1.4.2)
|
65
71
|
ansi
|
66
72
|
builder
|
67
73
|
minitest (>= 5.0)
|
68
74
|
ruby-progressbar
|
75
|
+
multi_xml (0.6.0)
|
69
76
|
mysql2 (0.5.3)
|
70
77
|
parallel (1.19.1)
|
71
78
|
parser (2.7.0.2)
|
@@ -80,7 +87,7 @@ GEM
|
|
80
87
|
rack (2.2.3)
|
81
88
|
rainbow (3.0.0)
|
82
89
|
rake (12.3.3)
|
83
|
-
rake-compiler (1.
|
90
|
+
rake-compiler (1.1.1)
|
84
91
|
rake
|
85
92
|
rb-fsevent (0.10.3)
|
86
93
|
rb-inotify (0.10.1)
|
@@ -122,6 +129,7 @@ PLATFORMS
|
|
122
129
|
DEPENDENCIES
|
123
130
|
hiredis (= 0.6.3)
|
124
131
|
http_parser.rb (~> 0.6.0)
|
132
|
+
httparty (= 0.17.1)
|
125
133
|
jekyll (~> 3.8.6)
|
126
134
|
jekyll-remote-theme (~> 0.4.1)
|
127
135
|
jekyll-seo-tag (~> 2.6.1)
|
@@ -133,7 +141,7 @@ DEPENDENCIES
|
|
133
141
|
polyphony!
|
134
142
|
pry (= 0.13.1)
|
135
143
|
rack (>= 2.0.8, < 2.3.0)
|
136
|
-
rake-compiler (= 1.
|
144
|
+
rake-compiler (= 1.1.1)
|
137
145
|
redis (= 4.1.0)
|
138
146
|
rubocop (= 0.85.1)
|
139
147
|
sequel (= 5.34.0)
|
data/README.md
CHANGED
@@ -35,9 +35,9 @@
|
|
35
35
|
Polyphony is a library for building concurrent applications in Ruby. Polyphony
|
36
36
|
harnesses the power of [Ruby fibers](https://ruby-doc.org/core-2.5.1/Fiber.html)
|
37
37
|
to provide a cooperative, sequential coroutine-based concurrency model. Under
|
38
|
-
the hood, Polyphony uses
|
39
|
-
|
40
|
-
|
38
|
+
the hood, Polyphony uses
|
39
|
+
[io_uring](https://unixism.net/loti/what_is_io_uring.html) or
|
40
|
+
[libev](https://github.com/enki/libev) to maximize I/O performance.
|
41
41
|
|
42
42
|
## Features
|
43
43
|
|
data/Rakefile
CHANGED
@@ -23,4 +23,4 @@ task :docs do
|
|
23
23
|
exec 'RUBYOPT=-W0 jekyll serve -s docs -H ec2-18-156-117-172.eu-central-1.compute.amazonaws.com'
|
24
24
|
end
|
25
25
|
|
26
|
-
CLEAN.include "**/*.o", "**/*.so", "**/*.bundle", "**/*.jar", "pkg", "tmp"
|
26
|
+
CLEAN.include "**/*.o", "**/*.so", "**/*.so.*", "**/*.a", "**/*.bundle", "**/*.jar", "pkg", "tmp"
|
data/TODO.md
CHANGED
@@ -1,15 +1,15 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
-
|
4
|
-
|
5
|
-
|
6
|
-
debugging). Focus on examples that serve as "how-to".
|
7
|
-
|
8
|
-
0.45.1
|
9
|
-
|
1
|
+
- change fiber_trace method to return nil, change trace logic to use provided
|
2
|
+
arguments instead of return values for fiber events
|
3
|
+
- allow backend selection at runtime
|
4
|
+
- add Backend#timer_loop that does what throttled_loop does, on lower level
|
5
|
+
- Adapter for io/console (what does `IO#raw` do?)
|
10
6
|
- Adapter for Pry and IRB (Which fixes #5 and #6)
|
7
|
+
- Improve `#supervise`. It does not work as advertised, and seems to exhibit an
|
8
|
+
inconsistent behaviour (see supervisor example).
|
9
|
+
- Fix backtrace for `Timeout.timeout` API (see timeout example).
|
10
|
+
- Check why worker-thread example doesn't work.
|
11
11
|
|
12
|
-
0.
|
12
|
+
0.47
|
13
13
|
|
14
14
|
- Debugging
|
15
15
|
- Eat your own dogfood: need a good tool to check what's going on when some
|
@@ -123,8 +123,6 @@
|
|
123
123
|
- discuss using `snooze` for ensuring responsiveness when executing CPU-bound work
|
124
124
|
|
125
125
|
|
126
|
-
## 0.47
|
127
|
-
|
128
126
|
### Some more API work, more docs
|
129
127
|
|
130
128
|
- sintra app with database access (postgresql)
|
@@ -136,14 +134,10 @@
|
|
136
134
|
- proceed from there
|
137
135
|
|
138
136
|
|
139
|
-
## 0.48
|
140
|
-
|
141
137
|
### Sinatra / Sidekiq
|
142
138
|
|
143
139
|
- Pull out redis/postgres code, put into new `polyphony-xxx` gems
|
144
140
|
|
145
|
-
## 0.49
|
146
|
-
|
147
141
|
### Testing && Docs
|
148
142
|
|
149
143
|
- More tests
|
@@ -154,8 +148,6 @@
|
|
154
148
|
- `IO.foreach`
|
155
149
|
- `Process.waitpid`
|
156
150
|
|
157
|
-
## 0.50 DNS
|
158
|
-
|
159
151
|
### DNS client
|
160
152
|
|
161
153
|
```ruby
|
@@ -6,7 +6,7 @@ require 'json'
|
|
6
6
|
|
7
7
|
X_SESSIONS = 1000
|
8
8
|
X_NODES = 10_000
|
9
|
-
X_SUBSCRIPTIONS_PER_SESSION =
|
9
|
+
X_SUBSCRIPTIONS_PER_SESSION = 1000
|
10
10
|
|
11
11
|
$sessions = []
|
12
12
|
X_SESSIONS.times do
|
@@ -17,8 +17,11 @@ X_SESSIONS.times do
|
|
17
17
|
}
|
18
18
|
end
|
19
19
|
|
20
|
+
REDIS_HOST = ENV['REDIS_HOST'] || 'localhost'
|
21
|
+
p redis_host: REDIS_HOST
|
22
|
+
|
20
23
|
spin do
|
21
|
-
redis = Redis.new
|
24
|
+
redis = Redis.new(host: REDIS_HOST)
|
22
25
|
redis.subscribe('events') do |on|
|
23
26
|
on.message do |_, message|
|
24
27
|
distribute_event(JSON.parse(message, symbolize_names: true))
|
@@ -30,18 +33,18 @@ $update_count = 0
|
|
30
33
|
|
31
34
|
def distribute_event(event)
|
32
35
|
$update_count += 1
|
33
|
-
|
36
|
+
t0 = Time.now
|
34
37
|
count = 0
|
35
38
|
$sessions.each do |s|
|
36
39
|
count += 1 if s[:subscriptions].include?(event[:path])
|
37
40
|
end
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
+
elapsed = Time.now - t0
|
42
|
+
rate = X_SESSIONS / elapsed
|
43
|
+
puts "elapsed: #{elapsed} (#{rate}/s)" if $update_count % 100 == 0
|
41
44
|
end
|
42
45
|
|
43
46
|
spin do
|
44
|
-
redis = Redis.new
|
47
|
+
redis = Redis.new(host: REDIS_HOST)
|
45
48
|
throttled_loop(1000) do
|
46
49
|
redis.publish('events', { path: "node#{rand(X_NODES)}" }.to_json)
|
47
50
|
end
|
@@ -60,7 +63,7 @@ spin do
|
|
60
63
|
end
|
61
64
|
end
|
62
65
|
|
63
|
-
trap(
|
66
|
+
trap('SIGINT') do
|
64
67
|
puts 'bye...'
|
65
68
|
exit!
|
66
69
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony/adapters/sequel'
|
5
|
+
require 'polyphony/adapters/postgres'
|
6
|
+
|
7
|
+
URL = ENV['SEQUEL_URL'] || 'postgres://localhost/test'
|
8
|
+
|
9
|
+
x = 10000
|
10
|
+
query_count = 0
|
11
|
+
|
12
|
+
spin do
|
13
|
+
db = Sequel.connect(URL)
|
14
|
+
x.times { query_count += 1; db.execute('select 1 as test') }
|
15
|
+
end
|
16
|
+
|
17
|
+
spin do
|
18
|
+
db = Sequel.connect(URL)
|
19
|
+
x.times { query_count += 1; db.execute('select 2 as test') }
|
20
|
+
end
|
21
|
+
|
22
|
+
t0 = Time.now
|
23
|
+
Fiber.current.await_all_children
|
24
|
+
puts "query rate: #{query_count / (Time.now - t0)} reqs/s; count = #{query_count}"
|
File without changes
|
File without changes
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
spin do
|
7
|
+
puts 'two'
|
8
|
+
# spinning a fiber from the parent fiber allows us to schedule an operation to
|
9
|
+
# be performed even after the current fiber is terminated
|
10
|
+
Fiber.current.parent.spin { puts 'four' }
|
11
|
+
puts 'three'
|
12
|
+
end
|
13
|
+
|
14
|
+
puts 'one'
|
15
|
+
|
16
|
+
suspend
|
@@ -3,8 +3,10 @@
|
|
3
3
|
require 'bundler/setup'
|
4
4
|
require 'polyphony'
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
module GenServer
|
7
|
+
module_function
|
8
|
+
|
9
|
+
def start(receiver, *args)
|
8
10
|
fiber = spin do
|
9
11
|
state = receiver.initial_state(*args)
|
10
12
|
loop do
|
@@ -14,11 +16,10 @@ class GenServer
|
|
14
16
|
end
|
15
17
|
end
|
16
18
|
build_api(fiber, receiver)
|
17
|
-
snooze
|
18
19
|
fiber
|
19
20
|
end
|
20
21
|
|
21
|
-
def
|
22
|
+
def build_api(fiber, receiver)
|
22
23
|
receiver.methods(false).each do |m|
|
23
24
|
if m =~ /!$/
|
24
25
|
fiber.define_singleton_method(m) do |*args|
|
@@ -32,7 +33,7 @@ class GenServer
|
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
35
|
-
def
|
36
|
+
def cast(process, method, *args)
|
36
37
|
process << {
|
37
38
|
from: Fiber.current,
|
38
39
|
method: method,
|
@@ -40,7 +41,7 @@ class GenServer
|
|
40
41
|
}
|
41
42
|
end
|
42
43
|
|
43
|
-
def
|
44
|
+
def call(process, method, *args)
|
44
45
|
process << {
|
45
46
|
from: Fiber.current,
|
46
47
|
method: method,
|
@@ -50,21 +51,27 @@ class GenServer
|
|
50
51
|
end
|
51
52
|
end
|
52
53
|
|
54
|
+
# In a generic server the state is not held in an instance variable but rather
|
55
|
+
# passed as the first parameter to method calls. The return value of each method
|
56
|
+
# is an array consisting of the result and the potentially mutated state.
|
53
57
|
module Map
|
54
|
-
|
58
|
+
module_function
|
59
|
+
|
60
|
+
def initial_state(hash = {})
|
55
61
|
hash
|
56
62
|
end
|
57
63
|
|
58
|
-
def
|
64
|
+
def get(state, key)
|
59
65
|
[state[key], state]
|
60
66
|
end
|
61
67
|
|
62
|
-
def
|
68
|
+
def put!(state, key, value)
|
63
69
|
state[key] = value
|
64
70
|
[:noreply, state]
|
65
71
|
end
|
66
72
|
end
|
67
73
|
|
74
|
+
# start server with initial state
|
68
75
|
map_server = GenServer.start(Map, {foo: :bar})
|
69
76
|
|
70
77
|
puts 'getting value from map server'
|
File without changes
|
@@ -9,10 +9,12 @@ pong = spin_loop do
|
|
9
9
|
ping << 'pong'
|
10
10
|
end
|
11
11
|
|
12
|
-
ping =
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
ping = spin do
|
13
|
+
3.times do
|
14
|
+
pong << ['ping', Fiber.current]
|
15
|
+
msg = receive
|
16
|
+
puts msg
|
17
|
+
end
|
16
18
|
end
|
17
19
|
|
18
|
-
|
20
|
+
ping.await
|