polyphony 0.43.8 → 0.45.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +7 -1
- data/CHANGELOG.md +38 -0
- data/Gemfile.lock +13 -11
- data/README.md +20 -5
- data/Rakefile +1 -1
- data/TODO.md +16 -14
- data/bin/stress.rb +28 -0
- 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/sequel_mysql.rb +23 -0
- data/examples/adapters/sequel_mysql_pool.rb +33 -0
- data/examples/core/{xx-agent.rb → xx-backend.rb} +5 -5
- data/examples/core/xx-channels.rb +4 -2
- data/examples/core/xx-using-a-mutex.rb +2 -1
- data/examples/io/xx-pry.rb +18 -0
- data/examples/io/xx-rack_server.rb +71 -0
- data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +1 -1
- data/ext/polyphony/backend.h +41 -0
- data/ext/polyphony/event.c +86 -0
- data/ext/polyphony/extconf.rb +1 -1
- data/ext/polyphony/fiber.c +0 -5
- data/ext/polyphony/{libev_agent.c → libev_backend.c} +234 -228
- data/ext/polyphony/polyphony.c +4 -0
- data/ext/polyphony/polyphony.h +16 -16
- data/ext/polyphony/polyphony_ext.c +4 -2
- data/ext/polyphony/queue.c +52 -12
- data/ext/polyphony/thread.c +55 -42
- data/lib/polyphony.rb +25 -39
- data/lib/polyphony/adapters/irb.rb +2 -17
- data/lib/polyphony/adapters/mysql2.rb +19 -0
- data/lib/polyphony/adapters/postgres.rb +5 -5
- data/lib/polyphony/adapters/process.rb +2 -2
- data/lib/polyphony/adapters/readline.rb +17 -0
- data/lib/polyphony/adapters/sequel.rb +45 -0
- data/lib/polyphony/core/channel.rb +3 -34
- data/lib/polyphony/core/exceptions.rb +11 -0
- data/lib/polyphony/core/global_api.rb +11 -6
- data/lib/polyphony/core/resource_pool.rb +22 -71
- data/lib/polyphony/core/sync.rb +48 -9
- data/lib/polyphony/core/throttler.rb +1 -1
- data/lib/polyphony/extensions/core.rb +37 -19
- data/lib/polyphony/extensions/fiber.rb +5 -1
- data/lib/polyphony/extensions/io.rb +7 -8
- data/lib/polyphony/extensions/openssl.rb +6 -6
- data/lib/polyphony/extensions/socket.rb +12 -22
- data/lib/polyphony/extensions/thread.rb +6 -5
- data/lib/polyphony/net.rb +2 -1
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +6 -3
- data/test/helper.rb +1 -1
- data/test/{test_agent.rb → test_backend.rb} +22 -22
- data/test/test_event.rb +1 -0
- data/test/test_fiber.rb +21 -5
- data/test/test_io.rb +1 -1
- data/test/test_kernel.rb +5 -0
- data/test/test_queue.rb +20 -0
- data/test/test_resource_pool.rb +34 -43
- data/test/test_signal.rb +5 -29
- data/test/test_sync.rb +52 -0
- metadata +74 -30
- data/.gitbook.yaml +0 -4
- data/lib/polyphony/event.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f9c8ab74213c6cc5e3852f73ee027ee496f2b04c6844e09856c9771ea5e7839a
|
4
|
+
data.tar.gz: 83d7c533024b6d6d633b9e18abc392911adfc07f728af826bd84cce35cafb20c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c42e49ebcd6fb10b384438cb7688801a387963bc2a6fb2c1d3de6d022a7731a7d88db138a34b364b35c9d71830b975a69cb1f14fb277166a9db1802e24e82dec
|
7
|
+
data.tar.gz: 6c578eacded00dd7a77a35124c69ebc966e4f9aa42264913df82af147f43955a2ecd86087630c085fcd4d6e964aa705202c5aa24bb4032648d3ba278d60d4f63
|
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
|
@@ -111,6 +112,7 @@ Style/Documentation:
|
|
111
112
|
Exclude:
|
112
113
|
- test/**/*.rb
|
113
114
|
- examples/**/*.rb
|
115
|
+
- lib/polyphony/adapters/**/*.rb
|
114
116
|
|
115
117
|
Style/FormatString:
|
116
118
|
Exclude:
|
@@ -172,4 +174,8 @@ Style/RedundantRegexpEscape:
|
|
172
174
|
Enabled: true
|
173
175
|
|
174
176
|
Style/SlicingWithRange:
|
175
|
-
Enabled: true
|
177
|
+
Enabled: true
|
178
|
+
|
179
|
+
Style/RaiseArgs:
|
180
|
+
Exclude:
|
181
|
+
- lib/polyphony/extensions/fiber.rb
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,41 @@
|
|
1
|
+
## 0.45.0
|
2
|
+
|
3
|
+
* Cleanup code
|
4
|
+
* Rename `Agent` to `Backend`
|
5
|
+
* Implement `Polyphony::ConditionVariable`
|
6
|
+
* Fix Kernel.system
|
7
|
+
|
8
|
+
## 0.44.0 2020-07-25
|
9
|
+
|
10
|
+
* Fix reentrant `ResourcePool` (#38)
|
11
|
+
* Add `ResourcePool#discard!` (#35)
|
12
|
+
* Add `Mysql2::Client` and `Sequel::ConnectionPool` adapters (#35)
|
13
|
+
* Reimplement `Kernel.trap` using `Fiber#interject`
|
14
|
+
* Add `Fiber#interject` for running arbitrary code on arbitrary fibers (#39)
|
15
|
+
|
16
|
+
## 0.43.11 2020-07-24
|
17
|
+
|
18
|
+
* Dump uncaught exception info for forked process (#36)
|
19
|
+
* Add additional socket config options (#37)
|
20
|
+
- :reuse_port (`SO_REUSEPORT`)
|
21
|
+
- :backlog (listen backlog, default `SOMAXCONN`)
|
22
|
+
* Fix possible race condition in Queue#shift (#34)
|
23
|
+
|
24
|
+
## 0.43.10 2020-07-23
|
25
|
+
|
26
|
+
* Fix race condition when terminating fibers (#33)
|
27
|
+
* Fix lock release in `Mutex` (#32)
|
28
|
+
* Virtualize agent interface
|
29
|
+
* Implement `LibevAgent_connect`
|
30
|
+
|
31
|
+
## 0.43.9 2020-07-22
|
32
|
+
|
33
|
+
* Rewrite `Channel` using `Queue`
|
34
|
+
* Rewrite `Mutex` using `Queue`
|
35
|
+
* Reimplement `Event` in C to prevent cross-thread race condition
|
36
|
+
* Reimplement `ResourcePool` using `Queue`
|
37
|
+
* Implement `Queue#size`
|
38
|
+
|
1
39
|
## 0.43.8 2020-07-21
|
2
40
|
|
3
41
|
* Rename `LibevQueue` to `Queue`
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
polyphony (0.
|
4
|
+
polyphony (0.45.0)
|
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,9 +23,6 @@ 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.0)
|
26
|
-
mime-types (~> 3.0)
|
27
|
-
multi_xml (>= 0.5.2)
|
28
26
|
i18n (0.9.5)
|
29
27
|
concurrent-ruby (~> 1.0)
|
30
28
|
jekyll (3.8.6)
|
@@ -60,25 +58,26 @@ GEM
|
|
60
58
|
listen (3.2.1)
|
61
59
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
62
60
|
rb-inotify (~> 0.9, >= 0.9.10)
|
63
|
-
localhost (1.1.4)
|
64
61
|
mercenary (0.3.6)
|
65
|
-
|
66
|
-
mime-types-data (~> 3.2015)
|
67
|
-
mime-types-data (3.2019.1009)
|
62
|
+
method_source (1.0.0)
|
68
63
|
minitest (5.13.0)
|
69
64
|
minitest-reporters (1.4.2)
|
70
65
|
ansi
|
71
66
|
builder
|
72
67
|
minitest (>= 5.0)
|
73
68
|
ruby-progressbar
|
74
|
-
|
69
|
+
mysql2 (0.5.3)
|
75
70
|
parallel (1.19.1)
|
76
71
|
parser (2.7.0.2)
|
77
72
|
ast (~> 2.4.0)
|
78
73
|
pathutil (0.16.2)
|
79
74
|
forwardable-extended (~> 2.6)
|
80
75
|
pg (1.1.4)
|
76
|
+
pry (0.13.1)
|
77
|
+
coderay (~> 1.1)
|
78
|
+
method_source (~> 1.0)
|
81
79
|
public_suffix (4.0.3)
|
80
|
+
rack (2.2.3)
|
82
81
|
rainbow (3.0.0)
|
83
82
|
rake (12.3.3)
|
84
83
|
rake-compiler (1.0.5)
|
@@ -109,6 +108,7 @@ GEM
|
|
109
108
|
sass-listen (4.0.0)
|
110
109
|
rb-fsevent (~> 0.9, >= 0.9.4)
|
111
110
|
rb-inotify (~> 0.9, >= 0.9.7)
|
111
|
+
sequel (5.34.0)
|
112
112
|
simplecov (0.17.1)
|
113
113
|
docile (~> 1.1)
|
114
114
|
json (>= 1.8, < 3)
|
@@ -122,19 +122,21 @@ PLATFORMS
|
|
122
122
|
DEPENDENCIES
|
123
123
|
hiredis (= 0.6.3)
|
124
124
|
http_parser.rb (~> 0.6.0)
|
125
|
-
httparty (= 0.17.0)
|
126
125
|
jekyll (~> 3.8.6)
|
127
126
|
jekyll-remote-theme (~> 0.4.1)
|
128
127
|
jekyll-seo-tag (~> 2.6.1)
|
129
128
|
just-the-docs (~> 0.3.0)
|
130
|
-
localhost (= 1.1.4)
|
131
129
|
minitest (= 5.13.0)
|
132
130
|
minitest-reporters (= 1.4.2)
|
131
|
+
mysql2 (= 0.5.3)
|
133
132
|
pg (= 1.1.4)
|
134
133
|
polyphony!
|
134
|
+
pry (= 0.13.1)
|
135
|
+
rack (>= 2.0.8, < 2.3.0)
|
135
136
|
rake-compiler (= 1.0.5)
|
136
137
|
redis (= 4.1.0)
|
137
138
|
rubocop (= 0.85.1)
|
139
|
+
sequel (= 5.34.0)
|
138
140
|
simplecov (= 0.17.1)
|
139
141
|
|
140
142
|
BUNDLED WITH
|
data/README.md
CHANGED
@@ -1,10 +1,25 @@
|
|
1
|
-
<
|
1
|
+
<h1 align="center">
|
2
|
+
<a href="https://digital-fabric.github.io/polyphony/">
|
3
|
+
<img src="docs/polyphony-logo.png" alt="Polyphony">
|
4
|
+
</a>
|
5
|
+
<br>
|
6
|
+
Polyphony
|
7
|
+
<br>
|
8
|
+
</h1>
|
2
9
|
|
3
|
-
|
10
|
+
<h4 align="center">Fine-Grained Concurrency for Ruby</h4>
|
4
11
|
|
5
|
-
|
6
|
-
|
7
|
-
|
12
|
+
<p align="center">
|
13
|
+
<a href="http://rubygems.org/gems/polyphony">
|
14
|
+
<img src="https://badge.fury.io/rb/polyphony.svg" alt="Ruby gem">
|
15
|
+
</a>
|
16
|
+
<a href="https://github.com/digital-fabric/polyphony/actions?query=workflow%3ATests">
|
17
|
+
<img src="https://github.com/digital-fabric/polyphony/workflows/Tests/badge.svg" alt="Tests">
|
18
|
+
</a>
|
19
|
+
<a href="https://github.com/digital-fabric/polyphony/blob/master/LICENSE">
|
20
|
+
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License">
|
21
|
+
</a>
|
22
|
+
</p>
|
8
23
|
|
9
24
|
[DOCS](https://digital-fabric.github.io/polyphony/) |
|
10
25
|
[EXAMPLES](examples)
|
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,13 +1,19 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
-
|
5
|
-
-
|
1
|
+
0.45
|
2
|
+
|
3
|
+
- Review all code
|
4
|
+
- Cleanup C code
|
5
|
+
- Cleanup and annotate examples (and remove all the examples used for
|
6
|
+
debugging). Focus on examples that serve as "how-to".
|
7
|
+
|
8
|
+
0.45.1
|
9
|
+
|
10
|
+
- Adapter for Pry and IRB (Which fixes #5 and #6)
|
11
|
+
|
12
|
+
0.46.0
|
6
13
|
|
7
14
|
- Debugging
|
8
15
|
- Eat your own dogfood: need a good tool to check what's going on when some
|
9
16
|
test fails
|
10
|
-
- Needs to work with Pry (can write perhaps an extension for pry)
|
11
17
|
- First impl in Ruby using `TracePoint` API
|
12
18
|
- Mode of operation:
|
13
19
|
- Two parts: tracer and controller
|
@@ -117,7 +123,7 @@
|
|
117
123
|
- discuss using `snooze` for ensuring responsiveness when executing CPU-bound work
|
118
124
|
|
119
125
|
|
120
|
-
## 0.
|
126
|
+
## 0.47
|
121
127
|
|
122
128
|
### Some more API work, more docs
|
123
129
|
|
@@ -130,13 +136,13 @@
|
|
130
136
|
- proceed from there
|
131
137
|
|
132
138
|
|
133
|
-
## 0.
|
139
|
+
## 0.48
|
134
140
|
|
135
141
|
### Sinatra / Sidekiq
|
136
142
|
|
137
143
|
- Pull out redis/postgres code, put into new `polyphony-xxx` gems
|
138
144
|
|
139
|
-
## 0.
|
145
|
+
## 0.49
|
140
146
|
|
141
147
|
### Testing && Docs
|
142
148
|
|
@@ -148,11 +154,7 @@
|
|
148
154
|
- `IO.foreach`
|
149
155
|
- `Process.waitpid`
|
150
156
|
|
151
|
-
## 0.
|
152
|
-
|
153
|
-
### Real IO#gets and IO#read
|
154
|
-
|
155
|
-
## 0.48 DNS
|
157
|
+
## 0.50 DNS
|
156
158
|
|
157
159
|
### DNS client
|
158
160
|
|
data/bin/stress.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
`rake recompile`
|
5
|
+
|
6
|
+
count = ARGV[0] ? ARGV[0].to_i : 100
|
7
|
+
|
8
|
+
TEST_CMD = 'ruby test/run.rb'
|
9
|
+
|
10
|
+
def run_test(count)
|
11
|
+
puts "#{count}: running tests..."
|
12
|
+
system(TEST_CMD)
|
13
|
+
return if $?.exitstatus == 0
|
14
|
+
|
15
|
+
puts "Failure after #{count} tests"
|
16
|
+
exit!
|
17
|
+
end
|
18
|
+
|
19
|
+
trap('INT') { exit! }
|
20
|
+
t0 = Time.now
|
21
|
+
count.times { |i| run_test(i + 1) }
|
22
|
+
elapsed = Time.now - t0
|
23
|
+
puts format(
|
24
|
+
"Successfully ran %d tests in %f seconds (%f per test)",
|
25
|
+
count,
|
26
|
+
elapsed,
|
27
|
+
elapsed / count
|
28
|
+
)
|
@@ -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
|