polyphony 0.45.0 → 0.45.1
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 +1 -0
- data/CHANGELOG.md +10 -0
- data/Gemfile.lock +9 -1
- data/TODO.md +6 -7
- data/examples/adapters/redis_client.rb +3 -1
- data/examples/adapters/redis_pubsub_perf.rb +11 -8
- data/examples/adapters/sequel_mysql.rb +1 -1
- data/examples/adapters/sequel_pg.rb +24 -0
- data/examples/core/{02-awaiting-fibers.rb → await.rb} +0 -0
- data/examples/core/{xx-channels.rb → channels.rb} +0 -0
- data/examples/core/deferring-an-operation.rb +16 -0
- data/examples/core/{xx-erlang-style-genserver.rb → erlang-style-genserver.rb} +16 -9
- data/examples/core/{xx-forking.rb → forking.rb} +1 -1
- data/examples/core/handling-signals.rb +11 -0
- data/examples/core/{03-interrupting.rb → interrupt.rb} +0 -0
- data/examples/core/{xx-pingpong.rb → pingpong.rb} +7 -5
- data/examples/core/{xx-recurrent-timer.rb → recurrent-timer.rb} +1 -1
- data/examples/core/{xx-resource_delegate.rb → resource_delegate.rb} +3 -4
- data/examples/core/{01-spinning-up-fibers.rb → spin.rb} +1 -1
- data/examples/core/{xx-spin_error_backtrace.rb → spin_error_backtrace.rb} +1 -1
- data/examples/core/{xx-supervise-process.rb → supervise-process.rb} +8 -5
- data/examples/core/supervisor.rb +20 -0
- data/examples/core/{xx-thread-sleep.rb → thread-sleep.rb} +0 -0
- data/examples/core/{xx-thread_pool.rb → thread_pool.rb} +0 -0
- data/examples/core/{xx-throttling.rb → throttling.rb} +0 -0
- data/examples/core/{xx-timeout.rb → timeout.rb} +0 -0
- data/examples/core/{xx-using-a-mutex.rb → using-a-mutex.rb} +0 -0
- data/examples/core/{xx-worker-thread.rb → worker-thread.rb} +2 -2
- data/examples/io/{xx-backticks.rb → backticks.rb} +0 -0
- data/examples/io/{xx-echo_client.rb → echo_client.rb} +1 -1
- data/examples/io/{xx-echo_client_from_stdin.rb → echo_client_from_stdin.rb} +2 -2
- data/examples/io/{xx-echo_pipe.rb → echo_pipe.rb} +1 -1
- data/examples/io/{xx-echo_server.rb → echo_server.rb} +0 -0
- data/examples/io/{xx-echo_server_with_timeout.rb → echo_server_with_timeout.rb} +1 -1
- data/examples/io/{xx-echo_stdin.rb → echo_stdin.rb} +0 -0
- data/examples/io/{xx-happy-eyeballs.rb → happy-eyeballs.rb} +0 -0
- data/examples/io/{xx-httparty.rb → httparty.rb} +4 -13
- data/examples/io/{xx-irb.rb → irb.rb} +0 -0
- data/examples/io/{xx-net-http.rb → net-http.rb} +0 -0
- data/examples/io/{xx-open.rb → open.rb} +0 -0
- data/examples/io/{xx-pry.rb → pry.rb} +0 -0
- data/examples/io/{xx-rack_server.rb → rack_server.rb} +0 -0
- data/examples/io/{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/{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/threaded_server.rb +1 -5
- data/examples/performance/thread_pool_perf.rb +6 -7
- data/ext/polyphony/backend.h +0 -1
- data/ext/polyphony/libev_backend.c +69 -68
- data/ext/polyphony/polyphony.c +0 -2
- data/ext/polyphony/polyphony.h +0 -13
- data/ext/polyphony/polyphony_ext.c +1 -2
- data/ext/polyphony/queue.c +3 -4
- data/ext/polyphony/ring_buffer.c +0 -1
- data/ext/polyphony/thread.c +3 -4
- data/lib/polyphony/adapters/fs.rb +1 -1
- data/lib/polyphony/adapters/redis.rb +1 -1
- data/lib/polyphony/core/global_api.rb +4 -4
- data/lib/polyphony/core/sync.rb +11 -9
- data/lib/polyphony/extensions/core.rb +1 -6
- data/lib/polyphony/extensions/io.rb +40 -6
- data/lib/polyphony/extensions/socket.rb +11 -2
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +2 -1
- data/test/test_io.rb +16 -0
- data/test/test_socket.rb +17 -0
- data/test/test_throttler.rb +1 -0
- metadata +58 -72
- data/examples/adapters/concurrent-ruby.rb +0 -9
- data/examples/core/04-handling-signals.rb +0 -19
- data/examples/core/xx-at_exit.rb +0 -29
- data/examples/core/xx-backend.rb +0 -102
- data/examples/core/xx-caller.rb +0 -12
- data/examples/core/xx-daemon.rb +0 -14
- data/examples/core/xx-deadlock.rb +0 -8
- data/examples/core/xx-deferring-an-operation.rb +0 -14
- data/examples/core/xx-exception-backtrace.rb +0 -40
- data/examples/core/xx-fork-cleanup.rb +0 -22
- data/examples/core/xx-fork-spin.rb +0 -42
- data/examples/core/xx-fork-terminate.rb +0 -27
- data/examples/core/xx-move_on.rb +0 -23
- data/examples/core/xx-queue-async.rb +0 -120
- data/examples/core/xx-readpartial.rb +0 -18
- data/examples/core/xx-signals.rb +0 -16
- data/examples/core/xx-sleep-forever.rb +0 -9
- data/examples/core/xx-sleeping.rb +0 -25
- data/examples/core/xx-snooze-starve.rb +0 -16
- data/examples/core/xx-spin-fork.rb +0 -49
- data/examples/core/xx-state-machine.rb +0 -51
- data/examples/core/xx-stop.rb +0 -20
- data/examples/core/xx-supervisors.rb +0 -21
- data/examples/core/xx-thread-selector-sleep.rb +0 -51
- data/examples/core/xx-thread-selector-snooze.rb +0 -46
- data/examples/core/xx-thread-snooze.rb +0 -34
- data/examples/core/xx-timer-gc.rb +0 -17
- data/examples/core/xx-trace.rb +0 -79
- data/examples/performance/xx-array.rb +0 -11
- data/examples/performance/xx-fiber-switch.rb +0 -9
- data/examples/performance/xx-snooze.rb +0 -15
- data/examples/xx-spin.rb +0 -32
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5f54b88851ca73f121975839812e0a1ad5686d017199b83a6365deda2b656d3a
|
|
4
|
+
data.tar.gz: 92671a26215f19e36c0b0f49edb990a6818e2c64d7a8ed8bc9c4f2621a5de170
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fd3caf340b523eccb1f86b10e06996ec26704ed1906bd82188363fb5142901b585992df8d88d0ca20adc188e51a010144fba8f10843ba79503d2984f63a08a05
|
|
7
|
+
data.tar.gz: 2b44d80a6ac0bf3f0f42ece1b7d2008c3d0b933c1df11be7f698bbc9dae80341bd1d302a1e0ccaa56b223468b607b7f024bbaa949a88ff1c343028d6cd256ba5
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
polyphony (0.45.
|
|
4
|
+
polyphony (0.45.1)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
@@ -23,6 +23,9 @@ GEM
|
|
|
23
23
|
forwardable-extended (2.6.0)
|
|
24
24
|
hiredis (0.6.3)
|
|
25
25
|
http_parser.rb (0.6.0)
|
|
26
|
+
httparty (0.17.1)
|
|
27
|
+
mime-types (~> 3.0)
|
|
28
|
+
multi_xml (>= 0.5.2)
|
|
26
29
|
i18n (0.9.5)
|
|
27
30
|
concurrent-ruby (~> 1.0)
|
|
28
31
|
jekyll (3.8.6)
|
|
@@ -60,12 +63,16 @@ GEM
|
|
|
60
63
|
rb-inotify (~> 0.9, >= 0.9.10)
|
|
61
64
|
mercenary (0.3.6)
|
|
62
65
|
method_source (1.0.0)
|
|
66
|
+
mime-types (3.3.1)
|
|
67
|
+
mime-types-data (~> 3.2015)
|
|
68
|
+
mime-types-data (3.2020.0512)
|
|
63
69
|
minitest (5.13.0)
|
|
64
70
|
minitest-reporters (1.4.2)
|
|
65
71
|
ansi
|
|
66
72
|
builder
|
|
67
73
|
minitest (>= 5.0)
|
|
68
74
|
ruby-progressbar
|
|
75
|
+
multi_xml (0.6.0)
|
|
69
76
|
mysql2 (0.5.3)
|
|
70
77
|
parallel (1.19.1)
|
|
71
78
|
parser (2.7.0.2)
|
|
@@ -122,6 +129,7 @@ PLATFORMS
|
|
|
122
129
|
DEPENDENCIES
|
|
123
130
|
hiredis (= 0.6.3)
|
|
124
131
|
http_parser.rb (~> 0.6.0)
|
|
132
|
+
httparty (= 0.17.1)
|
|
125
133
|
jekyll (~> 3.8.6)
|
|
126
134
|
jekyll-remote-theme (~> 0.4.1)
|
|
127
135
|
jekyll-seo-tag (~> 2.6.1)
|
data/TODO.md
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
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
1
|
0.45.1
|
|
9
2
|
|
|
10
3
|
- Adapter for Pry and IRB (Which fixes #5 and #6)
|
|
4
|
+
- Redesign signal handling - the current mechanism is problematic in that it
|
|
5
|
+
does not address signals that do not kill, for instance HUP or USR1.
|
|
6
|
+
- Improve `#supervise`. It does not work as advertised, and seems to exhibit an
|
|
7
|
+
inconsistent behaviour (see supervisor example).
|
|
8
|
+
- Fix backtrace for `Timeout.timeout` API (see timeout example).
|
|
9
|
+
- Check why worker-thread example doesn't work.
|
|
11
10
|
|
|
12
11
|
0.46.0
|
|
13
12
|
|
|
@@ -6,7 +6,7 @@ require 'json'
|
|
|
6
6
|
|
|
7
7
|
X_SESSIONS = 1000
|
|
8
8
|
X_NODES = 10_000
|
|
9
|
-
X_SUBSCRIPTIONS_PER_SESSION =
|
|
9
|
+
X_SUBSCRIPTIONS_PER_SESSION = 1000
|
|
10
10
|
|
|
11
11
|
$sessions = []
|
|
12
12
|
X_SESSIONS.times do
|
|
@@ -17,8 +17,11 @@ X_SESSIONS.times do
|
|
|
17
17
|
}
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
REDIS_HOST = ENV['REDIS_HOST'] || 'localhost'
|
|
21
|
+
p redis_host: REDIS_HOST
|
|
22
|
+
|
|
20
23
|
spin do
|
|
21
|
-
redis = Redis.new
|
|
24
|
+
redis = Redis.new(host: REDIS_HOST)
|
|
22
25
|
redis.subscribe('events') do |on|
|
|
23
26
|
on.message do |_, message|
|
|
24
27
|
distribute_event(JSON.parse(message, symbolize_names: true))
|
|
@@ -30,18 +33,18 @@ $update_count = 0
|
|
|
30
33
|
|
|
31
34
|
def distribute_event(event)
|
|
32
35
|
$update_count += 1
|
|
33
|
-
|
|
36
|
+
t0 = Time.now
|
|
34
37
|
count = 0
|
|
35
38
|
$sessions.each do |s|
|
|
36
39
|
count += 1 if s[:subscriptions].include?(event[:path])
|
|
37
40
|
end
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
elapsed = Time.now - t0
|
|
42
|
+
rate = X_SESSIONS / elapsed
|
|
43
|
+
puts "elapsed: #{elapsed} (#{rate}/s)" if $update_count % 100 == 0
|
|
41
44
|
end
|
|
42
45
|
|
|
43
46
|
spin do
|
|
44
|
-
redis = Redis.new
|
|
47
|
+
redis = Redis.new(host: REDIS_HOST)
|
|
45
48
|
throttled_loop(1000) do
|
|
46
49
|
redis.publish('events', { path: "node#{rand(X_NODES)}" }.to_json)
|
|
47
50
|
end
|
|
@@ -60,7 +63,7 @@ spin do
|
|
|
60
63
|
end
|
|
61
64
|
end
|
|
62
65
|
|
|
63
|
-
trap(
|
|
66
|
+
trap('SIGINT') do
|
|
64
67
|
puts 'bye...'
|
|
65
68
|
exit!
|
|
66
69
|
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
require 'polyphony/adapters/sequel'
|
|
5
|
+
require 'polyphony/adapters/postgres'
|
|
6
|
+
|
|
7
|
+
URL = ENV['SEQUEL_URL'] || 'postgres://localhost/test'
|
|
8
|
+
|
|
9
|
+
x = 10000
|
|
10
|
+
query_count = 0
|
|
11
|
+
|
|
12
|
+
spin do
|
|
13
|
+
db = Sequel.connect(URL)
|
|
14
|
+
x.times { query_count += 1; db.execute('select 1 as test') }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
spin do
|
|
18
|
+
db = Sequel.connect(URL)
|
|
19
|
+
x.times { query_count += 1; db.execute('select 2 as test') }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
t0 = Time.now
|
|
23
|
+
Fiber.current.await_all_children
|
|
24
|
+
puts "query rate: #{query_count / (Time.now - t0)} reqs/s; count = #{query_count}"
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
require 'polyphony'
|
|
5
|
+
|
|
6
|
+
spin do
|
|
7
|
+
puts 'two'
|
|
8
|
+
# spinning a fiber from the parent fiber allows us to schedule an operation to
|
|
9
|
+
# be performed even after the current fiber is terminated
|
|
10
|
+
Fiber.current.parent.spin { puts 'four' }
|
|
11
|
+
puts 'three'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
puts 'one'
|
|
15
|
+
|
|
16
|
+
suspend
|
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
require 'bundler/setup'
|
|
4
4
|
require 'polyphony'
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
module GenServer
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def start(receiver, *args)
|
|
8
10
|
fiber = spin do
|
|
9
11
|
state = receiver.initial_state(*args)
|
|
10
12
|
loop do
|
|
@@ -14,11 +16,10 @@ class GenServer
|
|
|
14
16
|
end
|
|
15
17
|
end
|
|
16
18
|
build_api(fiber, receiver)
|
|
17
|
-
snooze
|
|
18
19
|
fiber
|
|
19
20
|
end
|
|
20
21
|
|
|
21
|
-
def
|
|
22
|
+
def build_api(fiber, receiver)
|
|
22
23
|
receiver.methods(false).each do |m|
|
|
23
24
|
if m =~ /!$/
|
|
24
25
|
fiber.define_singleton_method(m) do |*args|
|
|
@@ -32,7 +33,7 @@ class GenServer
|
|
|
32
33
|
end
|
|
33
34
|
end
|
|
34
35
|
|
|
35
|
-
def
|
|
36
|
+
def cast(process, method, *args)
|
|
36
37
|
process << {
|
|
37
38
|
from: Fiber.current,
|
|
38
39
|
method: method,
|
|
@@ -40,7 +41,7 @@ class GenServer
|
|
|
40
41
|
}
|
|
41
42
|
end
|
|
42
43
|
|
|
43
|
-
def
|
|
44
|
+
def call(process, method, *args)
|
|
44
45
|
process << {
|
|
45
46
|
from: Fiber.current,
|
|
46
47
|
method: method,
|
|
@@ -50,21 +51,27 @@ class GenServer
|
|
|
50
51
|
end
|
|
51
52
|
end
|
|
52
53
|
|
|
54
|
+
# In a generic server the state is not held in an instance variable but rather
|
|
55
|
+
# passed as the first parameter to method calls. The return value of each method
|
|
56
|
+
# is an array consisting of the result and the potentially mutated state.
|
|
53
57
|
module Map
|
|
54
|
-
|
|
58
|
+
module_function
|
|
59
|
+
|
|
60
|
+
def initial_state(hash = {})
|
|
55
61
|
hash
|
|
56
62
|
end
|
|
57
63
|
|
|
58
|
-
def
|
|
64
|
+
def get(state, key)
|
|
59
65
|
[state[key], state]
|
|
60
66
|
end
|
|
61
67
|
|
|
62
|
-
def
|
|
68
|
+
def put!(state, key, value)
|
|
63
69
|
state[key] = value
|
|
64
70
|
[:noreply, state]
|
|
65
71
|
end
|
|
66
72
|
end
|
|
67
73
|
|
|
74
|
+
# start server with initial state
|
|
68
75
|
map_server = GenServer.start(Map, {foo: :bar})
|
|
69
76
|
|
|
70
77
|
puts 'getting value from map server'
|
|
File without changes
|
|
@@ -9,10 +9,12 @@ pong = spin_loop do
|
|
|
9
9
|
ping << 'pong'
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
ping =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
ping = spin do
|
|
13
|
+
3.times do
|
|
14
|
+
pong << ['ping', Fiber.current]
|
|
15
|
+
msg = receive
|
|
16
|
+
puts msg
|
|
17
|
+
end
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
ping.await
|
|
@@ -10,7 +10,7 @@ class Number
|
|
|
10
10
|
|
|
11
11
|
def greet(other)
|
|
12
12
|
puts "You are number #{other}, I am number #{@id}"
|
|
13
|
-
sleep(0.
|
|
13
|
+
sleep rand(0.2..0.3)
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
16
|
|
|
@@ -25,7 +25,6 @@ def meet(number)
|
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
(4..10).each { |x| spin { meet(x) } }
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
every(10) { puts "uptime: #{Time.now - t0}" }
|
|
30
|
+
sleep 1
|
|
@@ -8,7 +8,7 @@ Exception.__disable_sanitized_backtrace__ = true
|
|
|
8
8
|
supervisor = spin do
|
|
9
9
|
puts "parent pid #{Process.pid}"
|
|
10
10
|
|
|
11
|
-
Polyphony
|
|
11
|
+
Polyphony.watch_process do
|
|
12
12
|
puts "child pid #{Process.pid}"
|
|
13
13
|
puts "go to sleep"
|
|
14
14
|
sleep 5
|
|
@@ -22,9 +22,12 @@ supervisor = spin do
|
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
begin
|
|
25
|
+
spin do
|
|
26
|
+
sleep 2.5
|
|
27
|
+
Process.kill('TERM', Process.pid)
|
|
28
|
+
end
|
|
29
|
+
supervisor.await
|
|
30
|
+
rescue SystemExit
|
|
31
|
+
supervisor.terminate
|
|
25
32
|
supervisor.await
|
|
26
|
-
rescue Interrupt
|
|
27
|
-
exit!
|
|
28
|
-
# supervisor.terminate
|
|
29
|
-
# supervisor.await
|
|
30
33
|
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
require 'polyphony'
|
|
5
|
+
|
|
6
|
+
def my_sleep(t)
|
|
7
|
+
puts "#{t} start"
|
|
8
|
+
sleep(t)
|
|
9
|
+
puts "#{t} done"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
spin { my_sleep(1) }
|
|
13
|
+
spin { my_sleep(2) }
|
|
14
|
+
spin { my_sleep(3) }
|
|
15
|
+
spin { puts "fiber count: #{Fiber.current.children.count}" }
|
|
16
|
+
snooze
|
|
17
|
+
|
|
18
|
+
puts "#{Time.now} supervising..."
|
|
19
|
+
supervise
|
|
20
|
+
puts "#{Time.now} done supervising"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|