polyphony 0.45.0 → 0.45.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|