polyphony 0.13 → 0.14
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/.gitbook.yaml +5 -0
- data/.gitignore +55 -0
- data/.rubocop.yml +49 -0
- data/CHANGELOG.md +13 -2
- data/Gemfile +3 -0
- data/Gemfile.lock +31 -0
- data/LICENSE +21 -0
- data/README.md +35 -18
- data/Rakefile +20 -0
- data/TODO.md +49 -0
- data/docs/getting-started/getting-started.md +10 -0
- data/docs/getting-started/tutorial.md +2 -0
- data/docs/summary.md +9 -0
- data/examples/core/cancel.rb +10 -0
- data/examples/core/channel_echo.rb +43 -0
- data/examples/core/enumerator.rb +14 -0
- data/examples/core/fork.rb +22 -0
- data/examples/core/genserver.rb +74 -0
- data/examples/core/lock.rb +20 -0
- data/examples/core/move_on.rb +11 -0
- data/examples/core/move_on_twice.rb +17 -0
- data/examples/core/move_on_with_ensure.rb +17 -0
- data/examples/core/multiple_async.rb +17 -0
- data/examples/core/nested_async.rb +18 -0
- data/examples/core/nested_cancel.rb +41 -0
- data/examples/core/nested_multiple_async.rb +19 -0
- data/examples/core/next_tick.rb +13 -0
- data/examples/core/pulse.rb +13 -0
- data/examples/core/resource.rb +29 -0
- data/examples/core/resource_cancel.rb +34 -0
- data/examples/core/resource_delegate.rb +32 -0
- data/examples/core/sleep.rb +9 -0
- data/examples/core/sleep2.rb +13 -0
- data/examples/core/spawn.rb +15 -0
- data/examples/core/spawn_cancel.rb +19 -0
- data/examples/core/spawn_error.rb +28 -0
- data/examples/core/supervisor.rb +22 -0
- data/examples/core/supervisor_with_cancel_scope.rb +24 -0
- data/examples/core/supervisor_with_error.rb +23 -0
- data/examples/core/supervisor_with_manual_move_on.rb +25 -0
- data/examples/core/thread.rb +30 -0
- data/examples/core/thread_cancel.rb +30 -0
- data/examples/core/thread_pool.rb +60 -0
- data/examples/core/throttle.rb +17 -0
- data/examples/fs/read.rb +37 -0
- data/examples/interfaces/pg_client.rb +38 -0
- data/examples/interfaces/pg_pool.rb +37 -0
- data/examples/interfaces/pg_query.rb +32 -0
- data/examples/interfaces/redis_channels.rb +119 -0
- data/examples/interfaces/redis_client.rb +21 -0
- data/examples/interfaces/redis_pubsub.rb +26 -0
- data/examples/interfaces/redis_pubsub_perf.rb +65 -0
- data/examples/io/config.ru +3 -0
- data/examples/io/echo_client.rb +22 -0
- data/examples/io/echo_server.rb +14 -0
- data/examples/io/echo_server_with_timeout.rb +33 -0
- data/examples/io/echo_stdin.rb +15 -0
- data/examples/io/happy_eyeballs.rb +32 -0
- data/examples/io/http_client.rb +19 -0
- data/examples/io/http_server.js +24 -0
- data/examples/io/http_server.rb +16 -0
- data/examples/io/http_server_forked.rb +27 -0
- data/examples/io/http_server_throttled.rb +16 -0
- data/examples/io/http_ws_server.rb +42 -0
- data/examples/io/https_client.rb +17 -0
- data/examples/io/https_server.rb +23 -0
- data/examples/io/https_wss_server.rb +46 -0
- data/examples/io/rack_server.rb +19 -0
- data/examples/io/rack_server_https.rb +24 -0
- data/examples/io/rack_server_https_forked.rb +32 -0
- data/examples/io/websocket_server.rb +33 -0
- data/examples/io/ws_page.html +34 -0
- data/examples/io/wss_page.html +34 -0
- data/examples/performance/perf_multi_snooze.rb +21 -0
- data/examples/performance/perf_snooze.rb +30 -0
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +63 -0
- data/examples/performance/thread-vs-fiber/threaded_server.rb +27 -0
- data/examples/streams/lines.rb +27 -0
- data/examples/streams/stdio.rb +18 -0
- data/ext/ev/async.c +168 -0
- data/ext/ev/child.c +169 -0
- data/ext/ev/ev.h +32 -0
- data/ext/ev/ev_ext.c +20 -0
- data/ext/ev/ev_module.c +222 -0
- data/ext/ev/io.c +405 -0
- data/ext/ev/libev.h +9 -0
- data/ext/ev/signal.c +119 -0
- data/ext/ev/timer.c +197 -0
- data/ext/libev/Changes +513 -0
- data/ext/libev/LICENSE +37 -0
- data/ext/libev/README +58 -0
- data/ext/libev/README.embed +3 -0
- data/ext/libev/ev.c +5214 -0
- data/ext/libev/ev.h +849 -0
- data/ext/libev/ev_epoll.c +285 -0
- data/ext/libev/ev_kqueue.c +218 -0
- data/ext/libev/ev_poll.c +151 -0
- data/ext/libev/ev_port.c +189 -0
- data/ext/libev/ev_select.c +316 -0
- data/ext/libev/ev_vars.h +204 -0
- data/ext/libev/ev_win32.c +162 -0
- data/ext/libev/ev_wrap.h +200 -0
- data/ext/libev/test_libev_win32.c +123 -0
- data/lib/polyphony.rb +7 -2
- data/lib/polyphony/core.rb +1 -1
- data/lib/polyphony/core/{coroutine.rb → coprocess.rb} +10 -10
- data/lib/polyphony/core/exceptions.rb +5 -5
- data/lib/polyphony/core/supervisor.rb +16 -16
- data/lib/polyphony/core/thread.rb +1 -1
- data/lib/polyphony/extensions/io.rb +43 -42
- data/lib/polyphony/extensions/kernel.rb +10 -34
- data/lib/polyphony/extensions/postgres.rb +3 -2
- data/lib/polyphony/extensions/redis.rb +1 -1
- data/lib/polyphony/extensions/socket.rb +8 -4
- data/lib/polyphony/extensions/ssl.rb +0 -54
- data/lib/polyphony/http/agent.rb +4 -10
- data/lib/polyphony/http/http1.rb +25 -25
- data/lib/polyphony/http/http1_request.rb +38 -26
- data/lib/polyphony/http/http2.rb +4 -5
- data/lib/polyphony/http/http2_request.rb +12 -18
- data/lib/polyphony/http/rack.rb +1 -3
- data/lib/polyphony/http/server.rb +9 -9
- data/lib/polyphony/net.rb +2 -2
- data/lib/polyphony/resource_pool.rb +5 -1
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony/websocket.rb +52 -0
- data/polyphony.gemspec +31 -0
- data/test/test_coprocess.rb +131 -0
- data/test/test_core.rb +274 -0
- data/test/test_ev.rb +117 -0
- data/test/test_io.rb +38 -0
- metadata +113 -7
- data/lib/polyphony/core/async.rb +0 -36
- data/lib/polyphony/net_old.rb +0 -299
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 78b1d2bf93b1562b6ef1010acdf4a30993d6fd8f40e001ab13a00606e0ed2137
|
|
4
|
+
data.tar.gz: ea0f410c483ee06da41e1acdd342f9fccadf87c51bbca258571d8f5d2c6048a5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 70af3ec736856b611bd1d4242f6430761b83382f88239a31a1a7e4124fbe6804153e08d248c03c61510c272f9511cdf7f6f4ada277eab2cbd6809f2e41daaa39
|
|
7
|
+
data.tar.gz: 678dad06dab6f6dbbccc23e39ac45e8045b4fdf0b2ea29959fd34e243d9d0f19f624ef80a8022f7dde4790e080302f59b06e65ec3ca26c9fe5efc4a70856f2c2
|
data/.gitbook.yaml
ADDED
data/.gitignore
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
*.gem
|
|
2
|
+
*.rbc
|
|
3
|
+
/.config
|
|
4
|
+
/coverage/
|
|
5
|
+
/InstalledFiles
|
|
6
|
+
/pkg/
|
|
7
|
+
/spec/reports/
|
|
8
|
+
/spec/examples.txt
|
|
9
|
+
/test/tmp/
|
|
10
|
+
/test/version_tmp/
|
|
11
|
+
/tmp/
|
|
12
|
+
|
|
13
|
+
# Used by dotenv library to load environment variables.
|
|
14
|
+
# .env
|
|
15
|
+
|
|
16
|
+
## Specific to RubyMotion:
|
|
17
|
+
.dat*
|
|
18
|
+
.repl_history
|
|
19
|
+
build/
|
|
20
|
+
*.bridgesupport
|
|
21
|
+
build-iPhoneOS/
|
|
22
|
+
build-iPhoneSimulator/
|
|
23
|
+
|
|
24
|
+
## Specific to RubyMotion (use of CocoaPods):
|
|
25
|
+
#
|
|
26
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
|
27
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
|
28
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
|
29
|
+
#
|
|
30
|
+
# vendor/Pods/
|
|
31
|
+
|
|
32
|
+
## Documentation cache and generated files:
|
|
33
|
+
/.yardoc/
|
|
34
|
+
/_yardoc/
|
|
35
|
+
/doc/
|
|
36
|
+
/rdoc/
|
|
37
|
+
|
|
38
|
+
## Environment normalization:
|
|
39
|
+
/.bundle/
|
|
40
|
+
/vendor/bundle
|
|
41
|
+
/lib/bundler/man/
|
|
42
|
+
|
|
43
|
+
# for a library or gem, you might want to ignore these files since the code is
|
|
44
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
45
|
+
# Gemfile.lock
|
|
46
|
+
# .ruby-version
|
|
47
|
+
# .ruby-gemset
|
|
48
|
+
|
|
49
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
|
50
|
+
.rvmrc
|
|
51
|
+
|
|
52
|
+
test.rb
|
|
53
|
+
.vscode
|
|
54
|
+
|
|
55
|
+
lib/ev_ext.bundle
|
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
TargetRubyVersion: 2.5
|
|
3
|
+
RubyInterpreters:
|
|
4
|
+
- ruby
|
|
5
|
+
Exclude:
|
|
6
|
+
- '**/*.gemspec'
|
|
7
|
+
- 'test/**/*.rb'
|
|
8
|
+
- 'examples/**/*.rb'
|
|
9
|
+
- 'Gemfile*'
|
|
10
|
+
|
|
11
|
+
Style/LambdaCall:
|
|
12
|
+
Enabled: false
|
|
13
|
+
# Style/ModuleFunction:
|
|
14
|
+
# Enabled: false
|
|
15
|
+
# Style/RegexpLiteral:
|
|
16
|
+
# Enabled: false
|
|
17
|
+
|
|
18
|
+
# Naming/MemoizedInstanceVariableName:
|
|
19
|
+
# Enabled: false
|
|
20
|
+
|
|
21
|
+
Style/Alias:
|
|
22
|
+
EnforcedStyle: prefer_alias_method
|
|
23
|
+
|
|
24
|
+
Style/SpecialGlobalVars:
|
|
25
|
+
Enabled: false
|
|
26
|
+
|
|
27
|
+
Style/ClassAndModuleChildren:
|
|
28
|
+
Enabled: false
|
|
29
|
+
|
|
30
|
+
Metrics/AbcSize:
|
|
31
|
+
Enabled: false
|
|
32
|
+
|
|
33
|
+
Style/MixinUsage:
|
|
34
|
+
Enabled: false
|
|
35
|
+
|
|
36
|
+
Style/MultilineBlockChain:
|
|
37
|
+
Enabled: false
|
|
38
|
+
|
|
39
|
+
Lint/RescueException:
|
|
40
|
+
Enabled: false
|
|
41
|
+
|
|
42
|
+
Lint/InheritException:
|
|
43
|
+
Enabled: false
|
|
44
|
+
|
|
45
|
+
Style/NumericPredicate:
|
|
46
|
+
Enabled: false
|
|
47
|
+
|
|
48
|
+
Style/TrivialAccessors:
|
|
49
|
+
Enabled: false
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
0.14 2019-05-17
|
|
2
|
+
---------------
|
|
3
|
+
|
|
4
|
+
* Use chunked encoding in HTTP 1 response
|
|
5
|
+
* Rewrite IO#read, #readpartial, #write in C (about 30% performance improvement)
|
|
6
|
+
* Add method delegation to `ResourcePool`
|
|
7
|
+
* Optimize PG::Connection#async_exec
|
|
8
|
+
* Fix Coprocess#cancel!
|
|
9
|
+
* Preliminary support for websocket (see `examples/io/http_ws_server.rb`)
|
|
10
|
+
* Rename `Coroutine` to `Coprocess`
|
|
11
|
+
|
|
1
12
|
0.13 2019-01-05
|
|
2
13
|
---------------
|
|
3
14
|
|
|
@@ -18,8 +29,8 @@
|
|
|
18
29
|
|
|
19
30
|
* Move reactor loop to secondary fiber, allow blocking operations on main
|
|
20
31
|
fiber.
|
|
21
|
-
* Example implementation of erlang-style generic server pattern (implement
|
|
22
|
-
|
|
32
|
+
* Example implementation of erlang-style generic server pattern (implement async
|
|
33
|
+
API to a coroutine)
|
|
23
34
|
* Implement coroutine mailboxes, Coroutine#<<, Coroutine#receive, Kernel.receive
|
|
24
35
|
for message passing
|
|
25
36
|
* Add Coroutine.current for getting current coroutine
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
polyphony (0.14)
|
|
5
|
+
http-2 (= 0.10.0)
|
|
6
|
+
http_parser.rb (= 0.6.0)
|
|
7
|
+
modulation (= 0.23)
|
|
8
|
+
|
|
9
|
+
GEM
|
|
10
|
+
remote: https://rubygems.org/
|
|
11
|
+
specs:
|
|
12
|
+
http-2 (0.10.0)
|
|
13
|
+
http_parser.rb (0.6.0)
|
|
14
|
+
localhost (1.1.4)
|
|
15
|
+
minitest (5.11.3)
|
|
16
|
+
modulation (0.23)
|
|
17
|
+
rake (12.3.2)
|
|
18
|
+
rake-compiler (1.0.5)
|
|
19
|
+
rake
|
|
20
|
+
|
|
21
|
+
PLATFORMS
|
|
22
|
+
ruby
|
|
23
|
+
|
|
24
|
+
DEPENDENCIES
|
|
25
|
+
localhost (= 1.1.4)
|
|
26
|
+
minitest (= 5.11.3)
|
|
27
|
+
polyphony!
|
|
28
|
+
rake-compiler (= 1.0.5)
|
|
29
|
+
|
|
30
|
+
BUNDLED WITH
|
|
31
|
+
1.17.2
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018 Sharon Rosner
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
CHANGED
|
@@ -19,7 +19,7 @@ supports Linux and MacOS only. This software is currently at the alpha stage.
|
|
|
19
19
|
Polyphony is a library for building concurrent applications in Ruby. Polyphony
|
|
20
20
|
harnesses the power of
|
|
21
21
|
[Ruby fibers](https://ruby-doc.org/core-2.5.1/Fiber.html) to provide a
|
|
22
|
-
cooperative, sequential
|
|
22
|
+
cooperative, sequential coprocess-based concurrency model. Under the hood,
|
|
23
23
|
Polyphony uses [libev](https://github.com/enki/libev) as a high-performance event
|
|
24
24
|
reactor that provides timers, I/O watchers and other asynchronous event
|
|
25
25
|
primitives.
|
|
@@ -31,16 +31,18 @@ takes care of context-switching automatically whenever a blocking call like
|
|
|
31
31
|
|
|
32
32
|
## Features
|
|
33
33
|
|
|
34
|
+
- **Full-blown, integrated, high-performance HTTP 1 / HTTP 2 / WebSocket server
|
|
35
|
+
with TLS/SSL termination and automatic ALPN protocol selection**.
|
|
34
36
|
- Co-operative scheduling of concurrent tasks using Ruby fibers.
|
|
35
37
|
- High-performance event reactor for handling I/O events and timers.
|
|
36
38
|
- Natural, sequential programming style that makes it easy to reason about
|
|
37
39
|
concurrent code.
|
|
38
|
-
-
|
|
40
|
+
- Abstractions and constructs for controlling the execution of concurrent code:
|
|
39
41
|
coprocesses, supervisors, cancel scopes, throttling, resource pools etc.
|
|
40
42
|
- Code can use native networking classes and libraries, growing support for
|
|
41
43
|
third-party gems such as `pg` and `redis`.
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
+
- HTTP 1 / HTTP 2 client
|
|
45
|
+
- Competitive performance and scalability characteristics, in terms of both
|
|
44
46
|
throughput and memory consumption.
|
|
45
47
|
|
|
46
48
|
## Prior Art
|
|
@@ -89,12 +91,12 @@ end
|
|
|
89
91
|
In the above example, both `sleep` calls will be executed concurrently, and thus
|
|
90
92
|
the program will take approximately only 1 second to execute. Note the lack of
|
|
91
93
|
any boilerplate relating to concurrency. Each `spawn` block starts a
|
|
92
|
-
*
|
|
94
|
+
*coprocess*, and is executed in sequential manner.
|
|
93
95
|
|
|
94
|
-
> **
|
|
95
|
-
> operations take place inside
|
|
96
|
-
> `Fiber`, which allows it to be suspended whenever a blocking operation is
|
|
97
|
-
> called, and resumed once that operation has been completed.
|
|
96
|
+
> **Coprocesses - the basic unit of concurrency**: In Polyphony, concurrent
|
|
97
|
+
> operations take place inside coprocesses. A `Coprocess` is executed on top of
|
|
98
|
+
> a `Fiber`, which allows it to be suspended whenever a blocking operation is
|
|
99
|
+
> called, and resumed once that operation has been completed. Coprocesses offer
|
|
98
100
|
> significant advantages over threads - they consume only about 10KB, switching
|
|
99
101
|
> between them is much faster than switching threads, and literally millions of
|
|
100
102
|
> them can be spawned without affecting performance*. Besides, Ruby does not yet
|
|
@@ -113,7 +115,7 @@ require 'polyphony'
|
|
|
113
115
|
|
|
114
116
|
server = TCPServer.open(1234)
|
|
115
117
|
while client = server.accept
|
|
116
|
-
# spawn starts a new
|
|
118
|
+
# spawn starts a new coprocess on a separate fiber
|
|
117
119
|
spawn {
|
|
118
120
|
while data = client.read rescue nil
|
|
119
121
|
client.write(data)
|
|
@@ -128,10 +130,10 @@ This example demonstrates several features of Polyphony:
|
|
|
128
130
|
server. The result of `server.accept` is also a native `TCPSocket` object.
|
|
129
131
|
There are no wrapper classes being used.
|
|
130
132
|
- The only hint of the code being concurrent is the use of `Kernel#spawn`,
|
|
131
|
-
which starts a new
|
|
133
|
+
which starts a new coprocess on a dedicated fiber. This allows serving
|
|
132
134
|
multiple clients at once. Whenever a blocking call is issued, such as
|
|
133
135
|
`#accept` or `#read`, execution is *yielded* to the event loop, which will
|
|
134
|
-
resume only those
|
|
136
|
+
resume only those coprocesses which are ready to be resumed.
|
|
135
137
|
- Exception handling is done using the normal Ruby constructs `raise`, `rescue`
|
|
136
138
|
and `ensure`. Exceptions never go unhandled (as might be the case with Ruby
|
|
137
139
|
threads), and must be dealt with explicitly. An unhandled exception will cause
|
|
@@ -224,9 +226,9 @@ In order to facilitate writing concurrent code, Polyphony provides additional
|
|
|
224
226
|
constructs that make it easier to spawn concurrent tasks and to control them.
|
|
225
227
|
|
|
226
228
|
`CancelScope` - an abstraction used to cancel the execution of one or more
|
|
227
|
-
|
|
229
|
+
coprocesses or supervisors. It usually works by defining a timeout for the
|
|
228
230
|
completion of a task. Any blocking operation can be cancelled, including
|
|
229
|
-
a
|
|
231
|
+
a coprocess or a supervisor. The developer may choose to cancel with or without
|
|
230
232
|
an exception with `cancel` or `move_on`, respectively. Cancel scopes are
|
|
231
233
|
typically started using `Kernel.cancel_after` and `Kernel.move_on`:
|
|
232
234
|
|
|
@@ -261,9 +263,24 @@ Pool = Polyphony::ResourcePool.new(limit: 5) {
|
|
|
261
263
|
}
|
|
262
264
|
```
|
|
263
265
|
|
|
264
|
-
|
|
265
|
-
to
|
|
266
|
-
|
|
266
|
+
You can also call arbitrary methods on the resource pool, which will be
|
|
267
|
+
delegated to the resource using `#method_missing`:
|
|
268
|
+
|
|
269
|
+
```ruby
|
|
270
|
+
# up to 5 concurrent connections
|
|
271
|
+
Pool = Polyphony::ResourcePool.new(limit: 5) {
|
|
272
|
+
# the block sets up the resource
|
|
273
|
+
PG.connect(...)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
1000.times {
|
|
277
|
+
spawn { p Pool.query('select 1') }
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
`Supervisor` - a class used to control one or more `Coprocess`s. It can be used
|
|
282
|
+
to start, stop and restart multiple coprocesses. A supervisor can also be
|
|
283
|
+
used for awaiting the completion of multiple coprocesses. It is usually started
|
|
267
284
|
using `Kernel.supervise`:
|
|
268
285
|
|
|
269
286
|
```ruby
|
|
@@ -289,7 +306,7 @@ result = Polyphony::ThreadPool.process { long_running_process }
|
|
|
289
306
|
`Throttler` - a mechanism for throttling an arbitrary task, such as sending of
|
|
290
307
|
emails, or crawling a website. A throttler is normally created using
|
|
291
308
|
`Kernel.throttle`, and can even be used to throttle operations across multiple
|
|
292
|
-
|
|
309
|
+
coprocesses:
|
|
293
310
|
|
|
294
311
|
```ruby
|
|
295
312
|
server = Net.tcp_listen(1234)
|
data/Rakefile
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
require "rake/clean"
|
|
5
|
+
|
|
6
|
+
# frozen_string_literal: true
|
|
7
|
+
|
|
8
|
+
require "rake/extensiontask"
|
|
9
|
+
Rake::ExtensionTask.new("ev_ext") do |ext|
|
|
10
|
+
ext.ext_dir = "ext/ev"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
task :default => [:compile, :test]
|
|
14
|
+
task :test do
|
|
15
|
+
Dir.glob('./test/test_*.rb').each { |file| require(file) }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# task default: %w[compile]# spec rubocop]
|
|
19
|
+
|
|
20
|
+
CLEAN.include "**/*.o", "**/*.so", "**/*.bundle", "**/*.jar", "pkg", "tmp"
|
data/TODO.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
## Testing
|
|
2
|
+
|
|
3
|
+
- test IO
|
|
4
|
+
- test TCP server / client
|
|
5
|
+
- test thread / thread_pool modules
|
|
6
|
+
|
|
7
|
+
## UDP socket
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
socket = UDPSocket.new
|
|
11
|
+
socket.bind("127.0.0.1", 1234)
|
|
12
|
+
|
|
13
|
+
socket.send "message-to-self", 0, "127.0.0.1", 1234
|
|
14
|
+
p socket.recvfrom(10)
|
|
15
|
+
#=> ["message-to", ["AF_INET", 4913, "localhost", "127.0.0.1"]]
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## DNS client
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
ip_address = DNS.lookup('google.com', 'A')
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Prior art:
|
|
25
|
+
|
|
26
|
+
- https://github.com/alexdalitz/dnsruby
|
|
27
|
+
- https://github.com/eventmachine/eventmachine/blob/master/lib/em/resolver.rb
|
|
28
|
+
- https://github.com/gmodarelli/em-resolv-replace/blob/master/lib/em-dns-resolver.rb
|
|
29
|
+
- https://github.com/socketry/async-dns
|
|
30
|
+
|
|
31
|
+
### DNS server
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
Server = import('../../lib/polyphony/dns/server')
|
|
35
|
+
|
|
36
|
+
server = Server.new do |transaction|
|
|
37
|
+
puts "got query from #{transaction.info[:client_ip_address]}"
|
|
38
|
+
transaction.questions.each do |q|
|
|
39
|
+
respond(transaction, q[:domain], q[:resource_class])
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
server.listen(port: 5300)
|
|
44
|
+
puts "listening on port 5300"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Prior art:
|
|
48
|
+
|
|
49
|
+
- https://github.com/socketry/async-dns
|
data/docs/summary.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'modulation'
|
|
4
|
+
|
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
|
6
|
+
|
|
7
|
+
def echo(rchan, wchan)
|
|
8
|
+
puts "start echoer"
|
|
9
|
+
while msg = rchan.receive
|
|
10
|
+
wchan << "you said: #{msg}"
|
|
11
|
+
end
|
|
12
|
+
ensure
|
|
13
|
+
puts "echoer stopped"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
chan1, chan2 = Polyphony::Channel.new, Polyphony::Channel.new
|
|
17
|
+
|
|
18
|
+
echoer = spawn { echo(chan1, chan2) }
|
|
19
|
+
|
|
20
|
+
spawn do
|
|
21
|
+
puts "start receiver"
|
|
22
|
+
while msg = chan2.receive
|
|
23
|
+
puts msg
|
|
24
|
+
$main.resume if msg =~ /world/
|
|
25
|
+
end
|
|
26
|
+
ensure
|
|
27
|
+
puts "receiver stopped"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
$main = spawn do
|
|
31
|
+
t0 = Time.now
|
|
32
|
+
puts "send hello"
|
|
33
|
+
chan1 << "hello"
|
|
34
|
+
puts "send world"
|
|
35
|
+
chan1 << "world"
|
|
36
|
+
|
|
37
|
+
suspend
|
|
38
|
+
|
|
39
|
+
puts "closing channels"
|
|
40
|
+
chan1.close
|
|
41
|
+
chan2.close
|
|
42
|
+
puts "done #{Time.now - t0}"
|
|
43
|
+
end
|