polyphony 0.70 → 0.73.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +1 -0
- data/.github/workflows/test.yml +3 -2
- data/.gitignore +3 -1
- data/CHANGELOG.md +32 -4
- data/Gemfile.lock +11 -11
- data/TODO.md +1 -1
- data/bin/pdbg +1 -1
- data/bin/polyphony-debug +0 -0
- data/bin/stress.rb +0 -0
- data/bin/test +0 -0
- data/docs/_user-guide/all-about-timers.md +1 -1
- data/docs/api-reference/exception.md +5 -1
- data/docs/api-reference/fiber.md +2 -2
- data/docs/faq.md +1 -1
- data/docs/getting-started/overview.md +8 -8
- data/docs/getting-started/tutorial.md +3 -3
- data/docs/main-concepts/concurrency.md +1 -1
- data/docs/main-concepts/extending.md +3 -3
- data/docs/main-concepts/fiber-scheduling.md +1 -1
- data/examples/core/calc.rb +37 -0
- data/examples/core/calc_with_restart.rb +40 -0
- data/examples/core/calc_with_supervise.rb +37 -0
- data/examples/core/message_based_supervision.rb +1 -1
- data/examples/core/ring.rb +29 -0
- data/examples/io/rack_server.rb +1 -1
- data/examples/io/tunnel.rb +1 -1
- data/examples/performance/fiber_transfer.rb +1 -1
- data/examples/performance/line_splitting.rb +1 -1
- data/examples/performance/thread-vs-fiber/compare.rb +1 -1
- data/ext/polyphony/backend_common.c +15 -9
- data/ext/polyphony/backend_common.h +1 -1
- data/ext/polyphony/backend_io_uring.c +56 -64
- data/ext/polyphony/backend_io_uring_context.c +1 -1
- data/ext/polyphony/backend_io_uring_context.h +1 -1
- data/ext/polyphony/backend_libev.c +36 -30
- data/ext/polyphony/extconf.rb +25 -13
- data/ext/polyphony/polyphony.h +5 -1
- data/ext/polyphony/queue.c +2 -2
- data/ext/polyphony/runqueue_ring_buffer.c +3 -2
- data/ext/polyphony/thread.c +1 -1
- data/lib/polyphony/adapters/irb.rb +11 -1
- data/lib/polyphony/{extensions → core}/debug.rb +0 -0
- data/lib/polyphony/core/global_api.rb +3 -6
- data/lib/polyphony/core/timer.rb +2 -2
- data/lib/polyphony/debugger.rb +3 -3
- data/lib/polyphony/extensions/exception.rb +45 -0
- data/lib/polyphony/extensions/fiber.rb +27 -9
- data/lib/polyphony/extensions/io.rb +2 -2
- data/lib/polyphony/extensions/{core.rb → kernel.rb} +0 -73
- data/lib/polyphony/extensions/openssl.rb +20 -5
- data/lib/polyphony/extensions/process.rb +19 -0
- data/lib/polyphony/extensions/socket.rb +3 -4
- data/lib/polyphony/extensions/timeout.rb +10 -0
- data/lib/polyphony/extensions.rb +9 -0
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +2 -5
- data/polyphony.gemspec +1 -1
- data/test/coverage.rb +2 -2
- data/test/stress.rb +1 -1
- data/test/test_backend.rb +12 -12
- data/test/test_event.rb +1 -1
- data/test/test_ext.rb +1 -1
- data/test/test_fiber.rb +52 -7
- data/test/test_global_api.rb +16 -3
- data/test/test_io.rb +3 -3
- data/test/test_process_supervision.rb +1 -1
- data/test/test_queue.rb +6 -6
- data/test/test_signal.rb +20 -1
- data/test/test_socket.rb +12 -10
- data/test/test_supervise.rb +85 -0
- data/test/test_sync.rb +2 -2
- data/test/test_thread.rb +22 -2
- data/test/test_thread_pool.rb +1 -1
- data/test/test_throttler.rb +1 -1
- data/test/test_timer.rb +2 -2
- data/test/test_trace.rb +1 -1
- metadata +13 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c1647a2b1735e71dd4adf19ff701a649198786c3055430a0941b93e0905cf9dc
|
4
|
+
data.tar.gz: d00f4541d6bab4d7852ced8c0a8e15b6756305ab1c9eab3f7931bf7a18cfd6fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ec65b272aad6089f9f5a0a208a1e2a537e306fd1fc5247bb5aa25df22ad135d37c771947287b4d4ce5e3e4d5c5d8ced4fef9bab2291a6b7300f7b22245dd70f
|
7
|
+
data.tar.gz: 245c18039397202618c4a70538878396048ce409f36e51ece94919cd1720020cc47e13f213020c378c4d6caa9017df1c5082cd292e5f7987f11730486a0b0c0a
|
data/.github/FUNDING.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
github: ciconia
|
data/.github/workflows/test.yml
CHANGED
@@ -16,15 +16,16 @@ jobs:
|
|
16
16
|
runs-on: ${{matrix.os}}
|
17
17
|
steps:
|
18
18
|
- uses: actions/checkout@v1
|
19
|
-
- uses:
|
19
|
+
- uses: ruby/setup-ruby@v1
|
20
20
|
with:
|
21
21
|
ruby-version: ${{matrix.ruby}}
|
22
|
+
bundler-cache: true # 'bundle install' and cache
|
22
23
|
- name: Install dependencies
|
23
24
|
run: |
|
24
25
|
gem install bundler
|
25
26
|
bundle install
|
26
27
|
- name: Show Linux kernel version
|
27
|
-
run: uname -
|
28
|
+
run: uname -a
|
28
29
|
- name: Compile C-extension
|
29
30
|
run: POLYPHONY_USE_LIBEV=1 bundle exec rake compile
|
30
31
|
- name: Run tests
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,31 @@
|
|
1
|
+
## 0.73.1 2021-12-17
|
2
|
+
|
3
|
+
- Fix Gemfile.lock
|
4
|
+
|
5
|
+
## 0.73 2021-12-16
|
6
|
+
|
7
|
+
- Refactor core extensions into separate files for each class
|
8
|
+
- Improve compatibility with Ruby 3.1
|
9
|
+
- Improve accuracy of `timer_loop`
|
10
|
+
|
11
|
+
## 0.72 2021-11-22
|
12
|
+
|
13
|
+
- Add support for supervising added child fibers
|
14
|
+
- Do not use io_uring under LinuxKit (#66)
|
15
|
+
- Fix error message in `Fiber#restart`
|
16
|
+
- refactor `runqueue_ring_buffer_mark`
|
17
|
+
- Fix setting up test server on random port
|
18
|
+
- Enhance `Fiber#supervise`
|
19
|
+
- Add support for specifying `restart: true` (same as `restart: :always`)
|
20
|
+
- Add support for supervising child fibers (when fibers are not specified)
|
21
|
+
- Add `Fiber#attach_all_children_to`
|
22
|
+
- Improve `SSLServer#accept` when `servername_cb` is set
|
23
|
+
- Fix `#supervise` in Ruby 3.0
|
24
|
+
|
25
|
+
## 0.71 2021-08-20
|
26
|
+
|
27
|
+
- Fix compilation on Ruby 3.0
|
28
|
+
|
1
29
|
## 0.70 2021-08-19
|
2
30
|
|
3
31
|
- New implementation for `#supervise`
|
@@ -23,7 +51,7 @@
|
|
23
51
|
## 0.66 2021-08-01
|
24
52
|
|
25
53
|
- Fix all splicing APIs on non-linux OSes (#63)
|
26
|
-
- Add GC marking of buffers when cancelling read/write ops in io_uring backend
|
54
|
+
- Add GC marking of buffers when cancelling read/write ops in io_uring backend
|
27
55
|
|
28
56
|
## 0.65 2021-07-29
|
29
57
|
|
@@ -87,7 +115,7 @@
|
|
87
115
|
## 0.55.0 2021-06-17
|
88
116
|
|
89
117
|
- Finish io_uring implementation of Backend#chain
|
90
|
-
- Reimplement io_uring op_context acquire/release algorithm (using ref count)
|
118
|
+
- Reimplement io_uring op_context acquire/release algorithm (using ref count)
|
91
119
|
- Fix #gets on sockets
|
92
120
|
- Redesign event anti-starvation mechanism
|
93
121
|
|
@@ -182,7 +210,7 @@
|
|
182
210
|
|
183
211
|
## 0.47.0 2020-11-10
|
184
212
|
|
185
|
-
- Implement `#spin_scope` used for creating blocking fiber scopes
|
213
|
+
- Implement `#spin_scope` used for creating blocking fiber scopes
|
186
214
|
- Reimplement `move_on_after`, `cancel_after`, `Timeout.timeout` using
|
187
215
|
`Backend#timeout` (avoids creating canceller fiber for most common use case)
|
188
216
|
- Implement `Backend#timeout` API
|
@@ -277,7 +305,7 @@
|
|
277
305
|
- Reimplement Event using `Agent#wait_event`
|
278
306
|
- Improve Queue shift queue performance
|
279
307
|
- Introduce `Agent#wait_event` API for waiting on asynchronous events
|
280
|
-
- Minimize `fcntl` syscalls in IO operations
|
308
|
+
- Minimize `fcntl` syscalls in IO operations
|
281
309
|
|
282
310
|
## 0.43.7 2020-07-20
|
283
311
|
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
polyphony (0.
|
4
|
+
polyphony (0.73.1)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -14,12 +14,12 @@ GEM
|
|
14
14
|
httparty (0.17.1)
|
15
15
|
mime-types (~> 3.0)
|
16
16
|
multi_xml (>= 0.5.2)
|
17
|
-
json (2.
|
18
|
-
localhost (1.1.
|
17
|
+
json (2.6.1)
|
18
|
+
localhost (1.1.9)
|
19
19
|
method_source (1.0.0)
|
20
|
-
mime-types (3.
|
20
|
+
mime-types (3.4.1)
|
21
21
|
mime-types-data (~> 3.2015)
|
22
|
-
mime-types-data (3.2021.
|
22
|
+
mime-types-data (3.2021.1115)
|
23
23
|
minitest (5.14.4)
|
24
24
|
minitest-reporters (1.4.2)
|
25
25
|
ansi
|
@@ -28,8 +28,8 @@ GEM
|
|
28
28
|
ruby-progressbar
|
29
29
|
msgpack (1.4.2)
|
30
30
|
multi_xml (0.6.0)
|
31
|
-
parallel (1.
|
32
|
-
parser (3.0.2
|
31
|
+
parallel (1.21.0)
|
32
|
+
parser (3.0.3.2)
|
33
33
|
ast (~> 2.4.1)
|
34
34
|
pry (0.13.1)
|
35
35
|
coderay (~> 1.1)
|
@@ -38,7 +38,7 @@ GEM
|
|
38
38
|
rake (13.0.6)
|
39
39
|
rake-compiler (1.1.1)
|
40
40
|
rake
|
41
|
-
regexp_parser (2.
|
41
|
+
regexp_parser (2.2.0)
|
42
42
|
rexml (3.2.5)
|
43
43
|
rubocop (0.85.1)
|
44
44
|
parallel (~> 1.10)
|
@@ -49,7 +49,7 @@ GEM
|
|
49
49
|
rubocop-ast (>= 0.0.3)
|
50
50
|
ruby-progressbar (~> 1.7)
|
51
51
|
unicode-display_width (>= 1.4.0, < 2.0)
|
52
|
-
rubocop-ast (1.
|
52
|
+
rubocop-ast (1.15.0)
|
53
53
|
parser (>= 3.0.1.1)
|
54
54
|
ruby-progressbar (1.11.0)
|
55
55
|
simplecov (0.17.1)
|
@@ -57,7 +57,7 @@ GEM
|
|
57
57
|
json (>= 1.8, < 3)
|
58
58
|
simplecov-html (~> 0.10.0)
|
59
59
|
simplecov-html (0.10.2)
|
60
|
-
unicode-display_width (1.
|
60
|
+
unicode-display_width (1.8.0)
|
61
61
|
|
62
62
|
PLATFORMS
|
63
63
|
ruby
|
@@ -75,4 +75,4 @@ DEPENDENCIES
|
|
75
75
|
simplecov (= 0.17.1)
|
76
76
|
|
77
77
|
BUNDLED WITH
|
78
|
-
2.
|
78
|
+
2.1.4
|
data/TODO.md
CHANGED
@@ -107,7 +107,7 @@
|
|
107
107
|
|
108
108
|
Hitting the breakpoint will show the current location in the source code
|
109
109
|
(with few lines before and after), and present a prompt for commands.
|
110
|
-
|
110
|
+
|
111
111
|
- commands:
|
112
112
|
- `step` / `up` / `skip` / `continue` etc. - step into, step out, step over, run
|
113
113
|
- `switch` - switch fiber
|
data/bin/pdbg
CHANGED
data/bin/polyphony-debug
CHANGED
File without changes
|
data/bin/stress.rb
CHANGED
File without changes
|
data/bin/test
CHANGED
File without changes
|
@@ -44,7 +44,7 @@ The `#sleep` forever call can be used for example in the main fiber when we do
|
|
44
44
|
all our work in other fibers, since once the main fiber terminates the program
|
45
45
|
exits.
|
46
46
|
|
47
|
-
## Doing Work Later
|
47
|
+
## Doing Work Later
|
48
48
|
|
49
49
|
While `#sleep` allows you to block execution of the current fiber, sometimes you
|
50
50
|
want to perform some work later, while not blocking the current fiber. This is done simply by spinning off another fiber:
|
@@ -3,15 +3,19 @@ layout: page
|
|
3
3
|
title: ::Exception
|
4
4
|
parent: API Reference
|
5
5
|
permalink: /api-reference/exception/
|
6
|
+
source_url: https://github.com/digital-fabric/polyphony/blob/master/lib/polyphony/extensions/core.rb
|
7
|
+
ruby_docs_url: https://rubyapi.org/3.0/o/exception
|
6
8
|
---
|
7
9
|
# ::Exception
|
8
10
|
|
9
|
-
[Ruby core Exception documentation](https://
|
11
|
+
[Ruby core Exception documentation](https://rubyapi.org/3.0/o/exception)
|
10
12
|
|
11
13
|
The core `Exception` class is enhanced to provide a better backtrace that takes
|
12
14
|
into account the fiber hierarchy. In addition, a `source_fiber` attribute allows
|
13
15
|
tracking the fiber from which an uncaught exception was propagated.
|
14
16
|
|
17
|
+
|
18
|
+
|
15
19
|
## Class Methods
|
16
20
|
|
17
21
|
## Instance methods
|
data/docs/api-reference/fiber.md
CHANGED
@@ -205,7 +205,7 @@ f.raise
|
|
205
205
|
Pops the first message from the fiber's mailbox. If no message is available,
|
206
206
|
`#receive` will block until a message is pushed to the mailbox. The received
|
207
207
|
message can be any kind of object. This method is complemented by
|
208
|
-
`Fiber#<<`/`Fiber#send`.
|
208
|
+
`Fiber#<<`/`Fiber#send`.
|
209
209
|
|
210
210
|
```ruby
|
211
211
|
spin { Fiber.current.parent << 'hello from child' }
|
@@ -328,7 +328,7 @@ Returns the fiber's current state, which can be any of the following:
|
|
328
328
|
Supervises all child fibers, optionally restarting any fiber that terminates.
|
329
329
|
|
330
330
|
The given `opts` argument controls the behaviour of the supervision. The
|
331
|
-
following options are currently supported:
|
331
|
+
following options are currently supported:
|
332
332
|
|
333
333
|
- `:restart`: restart options
|
334
334
|
- `nil` - Child fibers are not restarted (default behaviour).
|
data/docs/faq.md
CHANGED
@@ -99,7 +99,7 @@ In conclusion:
|
|
99
99
|
|
100
100
|
## If callbacks suck, why not use promises?
|
101
101
|
|
102
|
-
Promises have gained a lot of traction during the last few years as an
|
102
|
+
Promises have gained a lot of traction during the last few years as an
|
103
103
|
alternative to callbacks, above all in the Javascript community. While promises
|
104
104
|
have been at a certain point considered for use in Polyphony, they were not
|
105
105
|
found to offer enough of a benefit. Promises still cause split logic, are quite
|
@@ -114,7 +114,7 @@ single CPU core.
|
|
114
114
|
|
115
115
|
Nevertheless, Polyphony fully supports multithreading, with each thread having
|
116
116
|
its own fiber run queue and its own libev event loop. Polyphony even enables
|
117
|
-
cross-thread communication using [fiber messaging](#message-passing).
|
117
|
+
cross-thread communication using [fiber messaging](#message-passing).
|
118
118
|
|
119
119
|
## Fibers vs Callbacks
|
120
120
|
|
@@ -138,7 +138,7 @@ Fibers, in contrast, let the developer express the business logic in a
|
|
138
138
|
sequential, easy to read manner: do this, then that. State can be stored right
|
139
139
|
in the business logic, as local variables. And finally, the sequential
|
140
140
|
programming style makes it much easier to debug your code, since stack traces
|
141
|
-
contain the entire history of execution from the app's inception.
|
141
|
+
contain the entire history of execution from the app's inception.
|
142
142
|
|
143
143
|
## Structured Concurrency
|
144
144
|
|
@@ -229,7 +229,7 @@ normally or with an exception:
|
|
229
229
|
fiber1 = spin { sleep 1; raise 'foo' }
|
230
230
|
fiber2 = spin { sleep 1 }
|
231
231
|
|
232
|
-
supervise # blocks and then propagates the error raised in fiber1
|
232
|
+
supervise # blocks and then propagates the error raised in fiber1
|
233
233
|
```
|
234
234
|
|
235
235
|
## Message Passing
|
@@ -266,7 +266,7 @@ end
|
|
266
266
|
Notice how the state (the `subscribers` variable) stays local, and how the logic
|
267
267
|
of the chat room is expressed in a way that is both compact and easy to extend.
|
268
268
|
Also notice how the chat room is written as an infinite loop. This is a common
|
269
|
-
pattern in Polyphony, since fibers can always be stopped at any moment.
|
269
|
+
pattern in Polyphony, since fibers can always be stopped at any moment.
|
270
270
|
|
271
271
|
The code for handling a chat room user might be expressed as follows:
|
272
272
|
|
@@ -350,14 +350,14 @@ operations.
|
|
350
350
|
|
351
351
|
While a standard event loop-based solution would implement a blocking call
|
352
352
|
separately from the fiber scheduling, the system backend integrates the two to
|
353
|
-
create a blocking call that
|
353
|
+
create a blocking call that already knows how to switch and schedule fibers.
|
354
354
|
For example, in Polyphony all APIs having to do with reading from files or
|
355
355
|
sockets end up calling `Thread.current.backend.read`, which does all the work.
|
356
356
|
|
357
357
|
This design offers some major advantages over other designs. It minimizes memory
|
358
|
-
allocations
|
358
|
+
allocations of both Ruby objects and C structures. For example, instead of
|
359
359
|
having to allocate libev watchers on the heap and then pass them around, they
|
360
|
-
are allocated on the stack instead, which saves
|
360
|
+
are allocated on the stack instead, which saves both memory and CPU cycles.
|
361
361
|
|
362
362
|
In addition, the backend interface includes two methods that allow maximizing
|
363
363
|
server performance by accepting connections and reading from sockets in a tight
|
@@ -482,5 +482,5 @@ reach version 1.0. Here are some of the exciting directions we're working on.
|
|
482
482
|
|
483
483
|
- Support for more core and stdlib APIs
|
484
484
|
- More adapters for gems with C-extensions, such as `mysql`, `sqlite3` etc
|
485
|
-
- Use `io_uring` backend as alternative to the libev backend
|
485
|
+
- Use `io_uring` backend as alternative to the libev backend
|
486
486
|
- More concurrency constructs for building highly concurrent applications
|
@@ -51,7 +51,7 @@ multiple threads or processes, but this approach has numerous disavantages:
|
|
51
51
|
- Both threads and processes are limited to a few thousand at best on a single
|
52
52
|
machine. Trying to spawn a thread per client essentially limits the scaling
|
53
53
|
capacity of your system.
|
54
|
-
|
54
|
+
|
55
55
|
Polyphony eschews both threads and processes in favor of fibers as the basic
|
56
56
|
unit of concurrency. The idea is that any time a blocking I/O operation occurs,
|
57
57
|
the current fiber is paused, and another fiber which has been marked as
|
@@ -117,7 +117,7 @@ Here's the actual sequence of execution (in pseudo-code)
|
|
117
117
|
sleeper = spin { ... } # The main fiber spins up a new fiber marked as runnable
|
118
118
|
suspend # The main fiber suspends, waiting for all other work to finish
|
119
119
|
Thread.current.switch_fiber # Polyphony looks for other runnable fibers
|
120
|
-
|
120
|
+
|
121
121
|
# (sleeper fiber)
|
122
122
|
puts "Going to sleep..." # The sleeper fiber starts running
|
123
123
|
sleep 1 # The sleeper fiber goes to sleep
|
@@ -280,7 +280,7 @@ def handle_client(client)
|
|
280
280
|
rescue Polyphony::Cancel
|
281
281
|
client.puts 'Closing connection due to inactivity.'
|
282
282
|
rescue Polyphony::Terminate
|
283
|
-
# We add a handler for the Terminate exception, and give
|
283
|
+
# We add a handler for the Terminate exception, and give
|
284
284
|
client.puts 'Server is shutting down. You have 5 more seconds...'
|
285
285
|
move_on_after(5) do
|
286
286
|
client_loop(client)
|
@@ -133,7 +133,7 @@ fiber that's blocking on any arbitrary operation.
|
|
133
133
|
Some other constructs offered by Polyphony:
|
134
134
|
|
135
135
|
* `Mutex` - a mutex used to synchronize access to a single shared resource.
|
136
|
-
* `ResourcePool` - used for synchronizing access to a limited amount of shared
|
136
|
+
* `ResourcePool` - used for synchronizing access to a limited amount of shared
|
137
137
|
resources, for example a pool of database connections.
|
138
138
|
* `Throttler` - used for throttling repeating operations, for example throttling
|
139
139
|
access to a shared resource, or throttling incoming requests.
|
@@ -9,9 +9,9 @@ next_title: The Design of Polyphony
|
|
9
9
|
---
|
10
10
|
# Extending Polyphony
|
11
11
|
|
12
|
-
Polyphony was designed to ease the transition from blocking APIs and
|
12
|
+
Polyphony was designed to ease the transition from blocking APIs and
|
13
13
|
callback-based API to non-blocking, fiber-based ones. It is important to
|
14
|
-
understand that not all blocking calls can be easily converted into
|
14
|
+
understand that not all blocking calls can be easily converted into
|
15
15
|
non-blocking calls. That might be the case with Ruby gems based on C-extensions,
|
16
16
|
such as database libraries. In that case, Polyphony's built-in
|
17
17
|
[thread pool](#threadpool) might be used for offloading such blocking calls.
|
@@ -22,7 +22,7 @@ Some of the most common patterns in Ruby APIs is the callback pattern, in which
|
|
22
22
|
the API takes a block as a callback to be called upon completion of a task. One
|
23
23
|
such example can be found in the excellent
|
24
24
|
[http_parser.rb](https://github.com/tmm1/http_parser.rb/) gem, which is used by
|
25
|
-
Polyphony itself to provide HTTP 1 functionality. The `HTTP:Parser` provides
|
25
|
+
Polyphony itself to provide HTTP 1 functionality. The `HTTP:Parser` provides
|
26
26
|
multiple hooks, or callbacks, for being notified when an HTTP request is
|
27
27
|
complete. The typical callback-based setup is as follows:
|
28
28
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
# Kernel#spin starts a new fiber
|
7
|
+
@controller = spin do
|
8
|
+
@worker = spin do
|
9
|
+
loop do
|
10
|
+
# Each fiber has a mailbox for receiving messages
|
11
|
+
peer, op, x, y = receive
|
12
|
+
result = x.send(op, y)
|
13
|
+
# The result is sent back to the "client"
|
14
|
+
peer << result
|
15
|
+
end
|
16
|
+
end
|
17
|
+
# The controller fiber will block until the worker is done (but notice that
|
18
|
+
# the worker runs an infinite loop.)
|
19
|
+
@worker.await
|
20
|
+
end
|
21
|
+
|
22
|
+
def calc(op, x, y)
|
23
|
+
# Send the job to the worker fiber...
|
24
|
+
@worker << [Fiber.current, op, x, y]
|
25
|
+
# ... and wait for the result
|
26
|
+
receive
|
27
|
+
end
|
28
|
+
|
29
|
+
# wait for worker to start
|
30
|
+
snooze until @worker
|
31
|
+
|
32
|
+
p calc(:+, 2, 3)
|
33
|
+
p calc(:**, 2, 3)
|
34
|
+
p calc(:+, 2, nil)
|
35
|
+
|
36
|
+
# wait for the controller to terminate
|
37
|
+
@controller.await
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
# Kernel#spin starts a new fiber
|
7
|
+
@controller = spin do
|
8
|
+
@worker = spin do
|
9
|
+
loop do
|
10
|
+
# Each fiber has a mailbox for receiving messages
|
11
|
+
peer, op, x, y = receive
|
12
|
+
result = x.send(op, y)
|
13
|
+
# The result is sent back to the "client"
|
14
|
+
peer << result
|
15
|
+
end
|
16
|
+
end
|
17
|
+
# The controller fiber will block until the worker is done (but notice that
|
18
|
+
# the worker runs an infinite loop.)
|
19
|
+
@worker.await
|
20
|
+
rescue => e
|
21
|
+
puts "Uncaught exception in worker: #{e}. Restarting..."
|
22
|
+
@worker.restart
|
23
|
+
end
|
24
|
+
|
25
|
+
def calc(op, x, y)
|
26
|
+
# Send the job to the worker fiber...
|
27
|
+
@worker << [Fiber.current, op, x, y]
|
28
|
+
# ... and wait for the result
|
29
|
+
receive
|
30
|
+
end
|
31
|
+
|
32
|
+
# wait for worker to start
|
33
|
+
snooze until @worker
|
34
|
+
|
35
|
+
p calc(:+, 2, 3)
|
36
|
+
p calc(:**, 2, 3)
|
37
|
+
p calc(:+, 2, nil)
|
38
|
+
|
39
|
+
# wait for the controller to terminate
|
40
|
+
@controller.await
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
# Kernel#spin starts a new fiber
|
7
|
+
@controller = spin do
|
8
|
+
@worker = spin do
|
9
|
+
loop do
|
10
|
+
# Each fiber has a mailbox for receiving messages
|
11
|
+
peer, op, x, y = receive
|
12
|
+
result = x.send(op, y)
|
13
|
+
# The result is sent back to the "client"
|
14
|
+
peer << result
|
15
|
+
end
|
16
|
+
end
|
17
|
+
# The controller fiber will block until the worker is done (but notice that
|
18
|
+
# the worker runs an infinite loop.)
|
19
|
+
@worker.supervise(@worker, restart: :always)
|
20
|
+
end
|
21
|
+
|
22
|
+
def calc(op, x, y)
|
23
|
+
# Send the job to the worker fiber...
|
24
|
+
@worker << [Fiber.current, op, x, y]
|
25
|
+
# ... and wait for the result
|
26
|
+
receive
|
27
|
+
end
|
28
|
+
|
29
|
+
# wait for worker to start
|
30
|
+
snooze until @worker
|
31
|
+
|
32
|
+
p calc(:+, 2, 3)
|
33
|
+
p calc(:**, 2, 3)
|
34
|
+
p calc(:+, 2, nil)
|
35
|
+
|
36
|
+
# wait for the controller to terminate
|
37
|
+
@controller.await
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
M = 100
|
7
|
+
N = 10000
|
8
|
+
|
9
|
+
GC.disable
|
10
|
+
|
11
|
+
def monotonic_clock
|
12
|
+
::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
13
|
+
end
|
14
|
+
|
15
|
+
def spin_proc(next_fiber)
|
16
|
+
spin_loop { next_fiber << receive }
|
17
|
+
end
|
18
|
+
|
19
|
+
last = Fiber.current
|
20
|
+
N.times { last = spin_proc(last) }
|
21
|
+
|
22
|
+
snooze
|
23
|
+
t0 = monotonic_clock
|
24
|
+
M.times do
|
25
|
+
last << 'hello'
|
26
|
+
receive
|
27
|
+
end
|
28
|
+
elapsed = monotonic_clock - t0
|
29
|
+
puts "M=#{M} N=#{N} elapsed: #{elapsed}"
|
data/examples/io/rack_server.rb
CHANGED
data/examples/io/tunnel.rb
CHANGED