polyphony 0.44.0 → 0.45.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +8 -1
- data/CHANGELOG.md +41 -0
- data/Gemfile.lock +14 -8
- data/Rakefile +1 -1
- data/TODO.md +12 -15
- data/docs/_posts/2020-07-26-polyphony-0.44.md +77 -0
- data/docs/api-reference/thread.md +1 -1
- data/docs/getting-started/overview.md +14 -14
- data/docs/getting-started/tutorial.md +1 -1
- 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/pry.rb +18 -0
- data/examples/io/rack_server.rb +71 -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 -1
- data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +1 -1
- data/examples/performance/thread-vs-fiber/threaded_server.rb +1 -5
- data/examples/performance/thread_pool_perf.rb +6 -7
- data/ext/polyphony/backend.h +40 -0
- data/ext/polyphony/event.c +3 -3
- data/ext/polyphony/extconf.rb +1 -1
- data/ext/polyphony/fiber.c +90 -13
- data/ext/polyphony/{libev_agent.c → libev_backend.c} +226 -224
- data/ext/polyphony/polyphony.c +5 -7
- data/ext/polyphony/polyphony.h +18 -18
- data/ext/polyphony/polyphony_ext.c +5 -4
- data/ext/polyphony/queue.c +5 -6
- 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 +53 -102
- data/lib/polyphony.rb +15 -14
- data/lib/polyphony/adapters/fs.rb +1 -1
- data/lib/polyphony/adapters/irb.rb +2 -17
- data/lib/polyphony/adapters/mysql2.rb +1 -1
- data/lib/polyphony/adapters/postgres.rb +5 -5
- data/lib/polyphony/adapters/process.rb +2 -5
- data/lib/polyphony/adapters/readline.rb +17 -0
- data/lib/polyphony/adapters/redis.rb +1 -1
- data/lib/polyphony/adapters/sequel.rb +1 -1
- data/lib/polyphony/core/global_api.rb +19 -14
- data/lib/polyphony/core/resource_pool.rb +2 -2
- data/lib/polyphony/core/sync.rb +43 -3
- data/lib/polyphony/core/throttler.rb +1 -1
- data/lib/polyphony/extensions/core.rb +25 -32
- data/lib/polyphony/extensions/fiber.rb +22 -45
- data/lib/polyphony/extensions/io.rb +60 -16
- data/lib/polyphony/extensions/openssl.rb +6 -6
- data/lib/polyphony/extensions/socket.rb +14 -15
- data/lib/polyphony/extensions/thread.rb +6 -5
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +5 -3
- data/test/helper.rb +1 -1
- data/test/{test_agent.rb → test_backend.rb} +22 -22
- data/test/test_fiber.rb +13 -12
- data/test/test_global_api.rb +29 -0
- data/test/test_io.rb +59 -1
- data/test/test_kernel.rb +5 -0
- data/test/test_signal.rb +14 -11
- data/test/test_socket.rb +17 -0
- data/test/test_sync.rb +73 -0
- metadata +99 -98
- data/.gitbook.yaml +0 -4
- data/examples/adapters/concurrent-ruby.rb +0 -9
- data/examples/core/04-handling-signals.rb +0 -19
- data/examples/core/xx-agent.rb +0 -102
- data/examples/core/xx-at_exit.rb +0 -29
- 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
- data/ext/polyphony/agent.h +0 -41
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fe5d86b07fc6f29d01897a7790deac8f0544bb61dbd486fb8ea104dd315b0e80
|
|
4
|
+
data.tar.gz: 3e1086b9395d63835a09051c52b7f8496013f190149df35532333b6c27b74169
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d6c7a78a46b9084f60ee838e82b7cde6f287eea2c500f779e5014103a400da98dc066adef58631033591a8de5278cc4f7b95ba8dcdac3ad22ecd68668a7d68e4
|
|
7
|
+
data.tar.gz: d32e7def9aa63ecb5c53b46020079e3384809ff786478e0b87fce1b141abb85d3c69d1f490b1d0a3bcbfaf972a3779939ac42bec512b12132d3b46b159754de5
|
data/.rubocop.yml
CHANGED
|
@@ -81,6 +81,7 @@ Lint/SuppressedException:
|
|
|
81
81
|
- examples/**/*.rb
|
|
82
82
|
|
|
83
83
|
Metrics/MethodLength:
|
|
84
|
+
Max: 12
|
|
84
85
|
Exclude:
|
|
85
86
|
- lib/polyphony/http/server/rack.rb
|
|
86
87
|
- lib/polyphony/extensions/io.rb
|
|
@@ -95,6 +96,7 @@ Metrics/ModuleLength:
|
|
|
95
96
|
Metrics/ClassLength:
|
|
96
97
|
Exclude:
|
|
97
98
|
- lib/polyphony/http/server/http1.rb
|
|
99
|
+
- lib/polyphony/extensions/io.rb
|
|
98
100
|
- test/**/*.rb
|
|
99
101
|
- examples/**/*.rb
|
|
100
102
|
|
|
@@ -111,6 +113,7 @@ Style/Documentation:
|
|
|
111
113
|
Exclude:
|
|
112
114
|
- test/**/*.rb
|
|
113
115
|
- examples/**/*.rb
|
|
116
|
+
- lib/polyphony/adapters/**/*.rb
|
|
114
117
|
|
|
115
118
|
Style/FormatString:
|
|
116
119
|
Exclude:
|
|
@@ -172,4 +175,8 @@ Style/RedundantRegexpEscape:
|
|
|
172
175
|
Enabled: true
|
|
173
176
|
|
|
174
177
|
Style/SlicingWithRange:
|
|
175
|
-
Enabled: true
|
|
178
|
+
Enabled: true
|
|
179
|
+
|
|
180
|
+
Style/RaiseArgs:
|
|
181
|
+
Exclude:
|
|
182
|
+
- lib/polyphony/extensions/fiber.rb
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,44 @@
|
|
|
1
|
+
## 0.45.5
|
|
2
|
+
|
|
3
|
+
* Fix compilation error (#43)
|
|
4
|
+
* Add support for resetting move_on_after, cancel_after timeouts
|
|
5
|
+
* Optimize anti-event starvation polling
|
|
6
|
+
* Implement optimized runqueue for better performance
|
|
7
|
+
* Schedule parent with priority on uncaught exception
|
|
8
|
+
* Fix race condition in `Mutex#synchronize` (#41)
|
|
9
|
+
|
|
10
|
+
## 0.45.4
|
|
11
|
+
|
|
12
|
+
* Improve signal trapping mechanism
|
|
13
|
+
|
|
14
|
+
## 0.45.3
|
|
15
|
+
|
|
16
|
+
* Don't swallow error in `Process#kill_and_await`
|
|
17
|
+
* Add `Fiber#mailbox` attribute reader
|
|
18
|
+
* Fix bug in `Fiber.await`
|
|
19
|
+
* Implement `IO#getc`, `IO#getbyte`
|
|
20
|
+
|
|
21
|
+
## 0.45.2
|
|
22
|
+
|
|
23
|
+
* Rewrite `Fiber#<<`, `Fiber#await`, `Fiber#receive` in C
|
|
24
|
+
|
|
25
|
+
## 0.45.1
|
|
26
|
+
|
|
27
|
+
* Fix Net::HTTP compatibility
|
|
28
|
+
* Fix fs adapter
|
|
29
|
+
* Improve performance of IO#puts
|
|
30
|
+
* Mutex#synchronize
|
|
31
|
+
* Fix Socket#connect
|
|
32
|
+
* Cleanup code
|
|
33
|
+
* Improve support for Ruby 3 keyword args
|
|
34
|
+
|
|
35
|
+
## 0.45.0
|
|
36
|
+
|
|
37
|
+
* Cleanup code
|
|
38
|
+
* Rename `Agent` to `Backend`
|
|
39
|
+
* Implement `Polyphony::ConditionVariable`
|
|
40
|
+
* Fix Kernel.system
|
|
41
|
+
|
|
1
42
|
## 0.44.0 2020-07-25
|
|
2
43
|
|
|
3
44
|
* Fix reentrant `ResourcePool` (#38)
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
polyphony (0.
|
|
4
|
+
polyphony (0.45.5)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
@@ -11,6 +11,7 @@ GEM
|
|
|
11
11
|
ansi (1.5.0)
|
|
12
12
|
ast (2.4.0)
|
|
13
13
|
builder (3.2.4)
|
|
14
|
+
coderay (1.1.3)
|
|
14
15
|
colorator (1.1.0)
|
|
15
16
|
concurrent-ruby (1.1.6)
|
|
16
17
|
docile (1.3.2)
|
|
@@ -22,7 +23,7 @@ GEM
|
|
|
22
23
|
forwardable-extended (2.6.0)
|
|
23
24
|
hiredis (0.6.3)
|
|
24
25
|
http_parser.rb (0.6.0)
|
|
25
|
-
httparty (0.17.
|
|
26
|
+
httparty (0.17.1)
|
|
26
27
|
mime-types (~> 3.0)
|
|
27
28
|
multi_xml (>= 0.5.2)
|
|
28
29
|
i18n (0.9.5)
|
|
@@ -60,11 +61,11 @@ GEM
|
|
|
60
61
|
listen (3.2.1)
|
|
61
62
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
|
62
63
|
rb-inotify (~> 0.9, >= 0.9.10)
|
|
63
|
-
localhost (1.1.4)
|
|
64
64
|
mercenary (0.3.6)
|
|
65
|
+
method_source (1.0.0)
|
|
65
66
|
mime-types (3.3.1)
|
|
66
67
|
mime-types-data (~> 3.2015)
|
|
67
|
-
mime-types-data (3.
|
|
68
|
+
mime-types-data (3.2020.0512)
|
|
68
69
|
minitest (5.13.0)
|
|
69
70
|
minitest-reporters (1.4.2)
|
|
70
71
|
ansi
|
|
@@ -79,10 +80,14 @@ GEM
|
|
|
79
80
|
pathutil (0.16.2)
|
|
80
81
|
forwardable-extended (~> 2.6)
|
|
81
82
|
pg (1.1.4)
|
|
83
|
+
pry (0.13.1)
|
|
84
|
+
coderay (~> 1.1)
|
|
85
|
+
method_source (~> 1.0)
|
|
82
86
|
public_suffix (4.0.3)
|
|
87
|
+
rack (2.2.3)
|
|
83
88
|
rainbow (3.0.0)
|
|
84
89
|
rake (12.3.3)
|
|
85
|
-
rake-compiler (1.
|
|
90
|
+
rake-compiler (1.1.1)
|
|
86
91
|
rake
|
|
87
92
|
rb-fsevent (0.10.3)
|
|
88
93
|
rb-inotify (0.10.1)
|
|
@@ -124,18 +129,19 @@ PLATFORMS
|
|
|
124
129
|
DEPENDENCIES
|
|
125
130
|
hiredis (= 0.6.3)
|
|
126
131
|
http_parser.rb (~> 0.6.0)
|
|
127
|
-
httparty (= 0.17.
|
|
132
|
+
httparty (= 0.17.1)
|
|
128
133
|
jekyll (~> 3.8.6)
|
|
129
134
|
jekyll-remote-theme (~> 0.4.1)
|
|
130
135
|
jekyll-seo-tag (~> 2.6.1)
|
|
131
136
|
just-the-docs (~> 0.3.0)
|
|
132
|
-
localhost (= 1.1.4)
|
|
133
137
|
minitest (= 5.13.0)
|
|
134
138
|
minitest-reporters (= 1.4.2)
|
|
135
139
|
mysql2 (= 0.5.3)
|
|
136
140
|
pg (= 1.1.4)
|
|
137
141
|
polyphony!
|
|
138
|
-
|
|
142
|
+
pry (= 0.13.1)
|
|
143
|
+
rack (>= 2.0.8, < 2.3.0)
|
|
144
|
+
rake-compiler (= 1.1.1)
|
|
139
145
|
redis (= 4.1.0)
|
|
140
146
|
rubocop (= 0.85.1)
|
|
141
147
|
sequel (= 5.34.0)
|
data/Rakefile
CHANGED
|
@@ -20,7 +20,7 @@ task :stress_test do
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
task :docs do
|
|
23
|
-
exec 'RUBYOPT=-W0 jekyll serve -s docs -H ec2-
|
|
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
26
|
CLEAN.include "**/*.o", "**/*.so", "**/*.bundle", "**/*.jar", "pkg", "tmp"
|
data/TODO.md
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
- io_uring
|
|
2
|
+
|
|
3
|
+
0.46
|
|
4
|
+
|
|
5
|
+
- Adapter for io/console (what does `IO#raw` do?)
|
|
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
|
+
|
|
12
|
+
0.47
|
|
8
13
|
|
|
9
14
|
- Debugging
|
|
10
15
|
- Eat your own dogfood: need a good tool to check what's going on when some
|
|
@@ -118,8 +123,6 @@
|
|
|
118
123
|
- discuss using `snooze` for ensuring responsiveness when executing CPU-bound work
|
|
119
124
|
|
|
120
125
|
|
|
121
|
-
## 0.45
|
|
122
|
-
|
|
123
126
|
### Some more API work, more docs
|
|
124
127
|
|
|
125
128
|
- sintra app with database access (postgresql)
|
|
@@ -131,14 +134,10 @@
|
|
|
131
134
|
- proceed from there
|
|
132
135
|
|
|
133
136
|
|
|
134
|
-
## 0.46
|
|
135
|
-
|
|
136
137
|
### Sinatra / Sidekiq
|
|
137
138
|
|
|
138
139
|
- Pull out redis/postgres code, put into new `polyphony-xxx` gems
|
|
139
140
|
|
|
140
|
-
## 0.47
|
|
141
|
-
|
|
142
141
|
### Testing && Docs
|
|
143
142
|
|
|
144
143
|
- More tests
|
|
@@ -149,8 +148,6 @@
|
|
|
149
148
|
- `IO.foreach`
|
|
150
149
|
- `Process.waitpid`
|
|
151
150
|
|
|
152
|
-
## 0.48 DNS
|
|
153
|
-
|
|
154
151
|
### DNS client
|
|
155
152
|
|
|
156
153
|
```ruby
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Polyphony 0.44.1
|
|
2
|
+
|
|
3
|
+
## More performance, more compatibility, more robustness
|
|
4
|
+
|
|
5
|
+
The last three weeks have been very busy for Polyphony. Since I first presented
|
|
6
|
+
Polyphony here and elsewhere, 17 issues were closed, 10 pull requests were
|
|
7
|
+
merged, and 144 commits were made by 4 different authors. I'm really
|
|
8
|
+
excited about Polyphony and the momentum it seems to be gathering. Your
|
|
9
|
+
reactions have been very positive so far (it even got [tweeted by
|
|
10
|
+
Matz!](https://twitter.com/yukihiro_matz/status/1279289318083715073))
|
|
11
|
+
|
|
12
|
+
I'm even more excited about the contributions Polyphony is starting to get from
|
|
13
|
+
other developers. Thank you [Will](https://github.com/wjordan),
|
|
14
|
+
[Máximo](https://github.com/ElMassimo) and [Trent](https://github.com/misfo) for
|
|
15
|
+
your valuable contributions! Also, the Polyphony project has now got a logo
|
|
16
|
+
designed by my friend [Gérald Morales](https://webocube.com/).
|
|
17
|
+
|
|
18
|
+
I'd like to encourage other developers to get in on the action and start
|
|
19
|
+
contributing by testing Polyphony, creating issues and writing code and
|
|
20
|
+
documentation. Together we can make Polyphony a game-changer for developing
|
|
21
|
+
concurrent apps in Ruby, and finally put to rest the notion that "Ruby is slow"!
|
|
22
|
+
|
|
23
|
+
Since the last public release of Polyphony, we have focused on fixing bugs,
|
|
24
|
+
improving performance and introducing new features that improve the Polyphony
|
|
25
|
+
developer experience. Polyphony 0.44 is up to 20% percent faster than the
|
|
26
|
+
previous release, due notably to a new ring-buffer implementation used by the
|
|
27
|
+
fiber run queue and the `Polyphony::Queue` class, a new `Backend#read_loop` API
|
|
28
|
+
for tighter server loops, and minimizing `fcntl` syscalls when doing I/O. These
|
|
29
|
+
and other minor improvements have resulted in Polyphony first crossing the
|
|
30
|
+
50,000 requests per second threshold for the first time in a minimal [rack
|
|
31
|
+
server
|
|
32
|
+
example](https://github.com/digital-fabric/polyphony/blob/master/examples/io/xx-rack_server.rb).
|
|
33
|
+
|
|
34
|
+
Notable new features include a MySQL adapter, a Sequel adapter, and a new
|
|
35
|
+
`Fiber#interject` API that allows executing arbitrary code on arbitrary fibers.
|
|
36
|
+
|
|
37
|
+
We have also fixed numerous bugs, among which an issue building Polyphony on
|
|
38
|
+
MacOS, problems issuing `Net::HTTP` requests with secure URLs, an issue with
|
|
39
|
+
`YAML.load` and much more...
|
|
40
|
+
|
|
41
|
+
For the full list of changes please consult the [change log](https://github.com/digital-fabric/polyphony/blob/master/CHANGELOG.md).
|
|
42
|
+
|
|
43
|
+
## What's next for Polyphony?
|
|
44
|
+
|
|
45
|
+
The next release of Polyphony will focus on full support IRB and Pry. Being able
|
|
46
|
+
to run operations in the background in IRB and Pry can be very beneficial, most
|
|
47
|
+
of all when developing and when debugging running processes using `binding.pry`
|
|
48
|
+
for example.
|
|
49
|
+
|
|
50
|
+
Subsequent releases will introduce a whole new full-featured debugger for
|
|
51
|
+
fiber-aware concurrent apps, and eventually full support for Sequel, Sinatra,
|
|
52
|
+
Hanami, Sidekiq and other major areas of the Ruby ecosystem.
|
|
53
|
+
|
|
54
|
+
## Tipi - a polyphonic web server for Ruby
|
|
55
|
+
|
|
56
|
+
[Tipi](https://github.com/digital-fabric/tipi) is a new web server for Ruby
|
|
57
|
+
apps. It is intended to be *the* go-to app server for Ruby apps looking for
|
|
58
|
+
robustness, scalability and performance. Tipi already supports HTTP/1, HTTP/2,
|
|
59
|
+
WebSockets and SSL termination. It can currently drive simple Rack apps. In the
|
|
60
|
+
future Tipi will be fully compliant with the Rack specification, and will also
|
|
61
|
+
offer a static file server, a rich configuration and automatic TLS certificates
|
|
62
|
+
(using Let's Encrypt) out of the box.
|
|
63
|
+
|
|
64
|
+
For those wondering about performance, here are some preliminary numbers (see
|
|
65
|
+
disclaimer below):
|
|
66
|
+
|
|
67
|
+
- HTTP, hello world, single process: ~50000 requests/second
|
|
68
|
+
- HTTP, Rack hello world app, single process: ~33000 requests/second
|
|
69
|
+
- HTTP, Rack hello world, 4 worker processes: ~95000 requests/second
|
|
70
|
+
- HTTPS, hello world, single process: ~20000 requests/second
|
|
71
|
+
- HTTPS, hello world, 4 worker processes: ~72000 requests/second
|
|
72
|
+
|
|
73
|
+
Disclaimer: these numbers should be taken with a grain of salt. They do not
|
|
74
|
+
follow any established benchmarking methodology, and may vary significantly. The
|
|
75
|
+
different configurtations were benchmarked using the command: `wrk -d10 -t1 -c10
|
|
76
|
+
"<http|https>://127.0.0.1:1234/"` on the same machine (an `m2.xlarge` instance)
|
|
77
|
+
as the server. In the future Tipi's performance might substantially change. YMMV.
|
|
@@ -12,7 +12,7 @@ Polyphony enhances the core `Thread` class with APIs for switching and
|
|
|
12
12
|
scheduling fibers, and reimplements some of its APIs such as `Thread#raise`
|
|
13
13
|
using fibers which, incidentally, make it safe.
|
|
14
14
|
|
|
15
|
-
Each thread has its own run queue and its own system
|
|
15
|
+
Each thread has its own run queue and its own system backend. While running
|
|
16
16
|
multiple threads does not result in true parallelism in MRI Ruby, sometimes
|
|
17
17
|
multithreading is inevitable, for instance when using third-party gems that
|
|
18
18
|
spawn threads, or when calling blocking APIs that are not fiber-aware.
|
|
@@ -341,25 +341,25 @@ move_on_after(10) { perform_query }
|
|
|
341
341
|
cancel_after(10) { perform_query }
|
|
342
342
|
```
|
|
343
343
|
|
|
344
|
-
## The
|
|
344
|
+
## The Polyphony Backend
|
|
345
345
|
|
|
346
346
|
In order to implement automatic fiber switching when performing blocking
|
|
347
|
-
operations, Polyphony introduces a concept called the *system
|
|
348
|
-
|
|
347
|
+
operations, Polyphony introduces a concept called the *system backend*. The system
|
|
348
|
+
backend is an object having a uniform interface, that performs all blocking
|
|
349
349
|
operations.
|
|
350
350
|
|
|
351
351
|
While a standard event loop-based solution would implement a blocking call
|
|
352
|
-
separately from the fiber scheduling, the system
|
|
352
|
+
separately from the fiber scheduling, the system backend integrates the two to
|
|
353
353
|
create a blocking call that is 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
|
-
sockets end up calling `Thread.current.
|
|
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
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
360
|
are allocated on the stack instead, which saves up on both memory and CPU cycles.
|
|
361
361
|
|
|
362
|
-
In addition, the
|
|
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
|
|
364
364
|
loop. Here's a naive implementation of an HTTP/1 server:
|
|
365
365
|
|
|
@@ -372,7 +372,7 @@ def handle_client(socket)
|
|
|
372
372
|
reqs = []
|
|
373
373
|
parser.on_message_complete = proc { |env| reqs << { foo: :bar } }
|
|
374
374
|
|
|
375
|
-
Thread.current.
|
|
375
|
+
Thread.current.backend.read_loop(socket) do |data|
|
|
376
376
|
parser << data
|
|
377
377
|
reqs.each { |r| reply(socket, r) }
|
|
378
378
|
reqs.clear
|
|
@@ -388,20 +388,20 @@ end
|
|
|
388
388
|
server = TCPServer.open('0.0.0.0', 1234)
|
|
389
389
|
puts "listening on port 1234"
|
|
390
390
|
|
|
391
|
-
Thread.current.
|
|
391
|
+
Thread.current.backend.accept_loop(server) do |client|
|
|
392
392
|
spin { handle_client(client) }
|
|
393
393
|
end
|
|
394
394
|
```
|
|
395
395
|
|
|
396
|
-
The `#read_loop` and `#accept_loop`
|
|
396
|
+
The `#read_loop` and `#accept_loop` backend methods implement tight loops that
|
|
397
397
|
provide a significant boost to performance (up to +30% better throughput.)
|
|
398
398
|
|
|
399
|
-
Currently, Polyphony includes a single system
|
|
399
|
+
Currently, Polyphony includes a single system backend based on
|
|
400
400
|
[libev](http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod). In the future,
|
|
401
|
-
Polyphony will include other platform-specific system
|
|
402
|
-
|
|
401
|
+
Polyphony will include other platform-specific system backends, such as a Windows
|
|
402
|
+
backend using
|
|
403
403
|
[IOCP](https://docs.microsoft.com/en-us/windows/win32/fileio/i-o-completion-ports),
|
|
404
|
-
or an [io_uring](https://unixism.net/loti/what_is_io_uring.html)
|
|
404
|
+
or an [io_uring](https://unixism.net/loti/what_is_io_uring.html) backend,
|
|
405
405
|
which might be a game-changer for writing highly-concurrent Ruby-based web apps.
|
|
406
406
|
|
|
407
407
|
## Writing Web Apps with Polyphony
|
|
@@ -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`
|
|
485
|
+
- Use `io_uring` backend as alternative to the libev backend
|
|
486
486
|
- More concurrency constructs for building highly concurrent applications
|
|
@@ -123,7 +123,7 @@ suspend # The main fiber suspends, waiting for all other work to finish
|
|
|
123
123
|
sleep 1 # The sleeper fiber goes to sleep
|
|
124
124
|
Gyro::Timer.new(1, 0).await # A timer event watcher is setup and yields
|
|
125
125
|
Thread.current.switch_fiber # Polyphony looks for other runnable fibers
|
|
126
|
-
Thread.current.
|
|
126
|
+
Thread.current.backend.poll # With no work left, the event loop is ran
|
|
127
127
|
fiber.schedule # The timer event fires, scheduling the sleeper fiber
|
|
128
128
|
# <= The sleep method returns
|
|
129
129
|
puts "Woke up"
|
|
@@ -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
|