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
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'modulation'
|
|
4
|
+
Polyphony = import('../../lib/polyphony')
|
|
5
|
+
|
|
6
|
+
puts "parent pid: #{Process.pid}"
|
|
7
|
+
|
|
8
|
+
pid = Polyphony.fork do
|
|
9
|
+
puts "child pid: #{Process.pid}"
|
|
10
|
+
|
|
11
|
+
spawn do
|
|
12
|
+
puts "child going to sleep 1..."
|
|
13
|
+
sleep 1
|
|
14
|
+
puts "child woke up 1"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
puts "got child pid #{pid}"
|
|
19
|
+
|
|
20
|
+
puts "waiting for child"
|
|
21
|
+
EV::Child.new(pid).await
|
|
22
|
+
puts "child is done"
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'modulation'
|
|
4
|
+
|
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
|
6
|
+
|
|
7
|
+
class GenServer
|
|
8
|
+
def self.start(receiver, *args)
|
|
9
|
+
coprocess = spawn do
|
|
10
|
+
state = receiver.initial_state(*args)
|
|
11
|
+
loop do
|
|
12
|
+
msg = receive
|
|
13
|
+
reply, state = receiver.send(msg[:method], state, *msg[:args])
|
|
14
|
+
msg[:from] << reply unless reply == :noreply
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
build_api(coprocess, receiver)
|
|
18
|
+
EV.snooze
|
|
19
|
+
coprocess
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.build_api(coprocess, receiver)
|
|
23
|
+
receiver.methods(false).each do |m|
|
|
24
|
+
if m =~ /!$/
|
|
25
|
+
coprocess.define_singleton_method(m) do |*args|
|
|
26
|
+
GenServer.cast(coprocess, m, *args)
|
|
27
|
+
end
|
|
28
|
+
else
|
|
29
|
+
coprocess.define_singleton_method(m) do |*args|
|
|
30
|
+
GenServer.call(coprocess, m, *args)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.cast(process, method, *args)
|
|
37
|
+
process << {from: Polyphony::Coprocess.current, method: method, args: args}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.call(process, method, *args)
|
|
41
|
+
process << {from: Polyphony::Coprocess.current, method: method, args: args}
|
|
42
|
+
receive
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
module Map
|
|
47
|
+
def self.initial_state(hash = {})
|
|
48
|
+
hash
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def self.get(state, key)
|
|
52
|
+
[state[key], state]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def self.put!(state, key, value)
|
|
56
|
+
state[key] = value
|
|
57
|
+
[:noreply, state]
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
map_server = GenServer.start(Map, {foo: :bar})
|
|
62
|
+
|
|
63
|
+
puts "getting value from map server"
|
|
64
|
+
v = map_server.get(:foo)
|
|
65
|
+
puts "value: #{v.inspect}"
|
|
66
|
+
|
|
67
|
+
puts "putting value in map server"
|
|
68
|
+
map_server.put!(:foo, 42)
|
|
69
|
+
|
|
70
|
+
puts "getting value from map server"
|
|
71
|
+
v = map_server.get(:foo)
|
|
72
|
+
puts "value: #{v.inspect}"
|
|
73
|
+
|
|
74
|
+
map_server.stop
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'modulation'
|
|
4
|
+
|
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
|
6
|
+
|
|
7
|
+
def loop_it(number, lock)
|
|
8
|
+
loop do
|
|
9
|
+
sleep(rand*0.2)
|
|
10
|
+
lock.synchronize do
|
|
11
|
+
puts "child #{number} has the lock"
|
|
12
|
+
sleep(rand*0.05)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
lock = Polyphony::Sync::Mutex.new
|
|
18
|
+
spawn { loop_it(1, lock) }
|
|
19
|
+
spawn { loop_it(2, lock) }
|
|
20
|
+
spawn { loop_it(3, lock) }
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'modulation'
|
|
4
|
+
|
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
|
6
|
+
|
|
7
|
+
puts "going to sleep..."
|
|
8
|
+
move_on_after(1) do
|
|
9
|
+
sleep 60
|
|
10
|
+
end
|
|
11
|
+
puts "woke up"
|
|
12
|
+
|
|
13
|
+
puts "going to sleep..."
|
|
14
|
+
move_on_after(1) do
|
|
15
|
+
sleep 60
|
|
16
|
+
end
|
|
17
|
+
puts "woke up"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'modulation'
|
|
4
|
+
|
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
|
6
|
+
|
|
7
|
+
puts "going to sleep..."
|
|
8
|
+
move_on_after(0.5) do |scope|
|
|
9
|
+
begin
|
|
10
|
+
sleep 60
|
|
11
|
+
ensure
|
|
12
|
+
puts "in ensure (is it going to block?)"
|
|
13
|
+
# this should not block, since the scope was cancelled
|
|
14
|
+
sleep 10 unless scope.cancelled?
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
puts "woke up"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'modulation'
|
|
4
|
+
|
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
|
6
|
+
|
|
7
|
+
spawn do
|
|
8
|
+
puts "going to sleep"
|
|
9
|
+
result = async do
|
|
10
|
+
async do
|
|
11
|
+
async do
|
|
12
|
+
puts "Fiber count: #{Polyphony::FiberPool.size}"
|
|
13
|
+
sleep(1)
|
|
14
|
+
end.await
|
|
15
|
+
end.await
|
|
16
|
+
end.await
|
|
17
|
+
puts "result: #{result}"
|
|
18
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'modulation'
|
|
4
|
+
|
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
|
6
|
+
|
|
7
|
+
async def sleep_and_cancel
|
|
8
|
+
puts "#{Time.now} going to sleep with cancel..."
|
|
9
|
+
cancel_after(1) do
|
|
10
|
+
puts "#{Time.now} outer cancel scope"
|
|
11
|
+
cancel_after(10) do
|
|
12
|
+
puts "#{Time.now} inner cancel scope"
|
|
13
|
+
sleep 60
|
|
14
|
+
rescue Exception => e
|
|
15
|
+
puts "#{Time.now} inner scope got error: #{e}"
|
|
16
|
+
raise e
|
|
17
|
+
end
|
|
18
|
+
rescue Exception => e
|
|
19
|
+
puts "#{Time.now} outer scope got error: #{e}"
|
|
20
|
+
end
|
|
21
|
+
ensure
|
|
22
|
+
puts "#{Time.now} woke up"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
async def sleep_and_move_on
|
|
26
|
+
puts "#{Time.now} going to sleep with move_on..."
|
|
27
|
+
move_on_after(1) do
|
|
28
|
+
puts "#{Time.now} outer cancel scope"
|
|
29
|
+
move_on_after(10) do
|
|
30
|
+
puts "#{Time.now} inner cancel scope"
|
|
31
|
+
sleep 60
|
|
32
|
+
puts "#{Time.now} inner scope done"
|
|
33
|
+
end
|
|
34
|
+
puts "#{Time.now} outer scope done"
|
|
35
|
+
end
|
|
36
|
+
puts "#{Time.now} woke up"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
sleep_and_cancel.await
|
|
40
|
+
puts
|
|
41
|
+
sleep_and_move_on.await
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'modulation'
|
|
4
|
+
|
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
|
6
|
+
|
|
7
|
+
resource_count = 0
|
|
8
|
+
Pool = Polyphony::ResourcePool.new(limit: 3) do
|
|
9
|
+
:"resource#{resource_count += 1}"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
async def user(number)
|
|
13
|
+
loop do
|
|
14
|
+
# puts "user #{number} >"
|
|
15
|
+
Pool.acquire do |r|
|
|
16
|
+
puts "user #{number} #{r.inspect} >"
|
|
17
|
+
sleep(0.05 + rand * 0.2)
|
|
18
|
+
# STDOUT << '.'
|
|
19
|
+
# puts "#{number}: #{r.inspect}"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
100.times do |x|
|
|
25
|
+
spawn user(x)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
t0 = Time.now
|
|
29
|
+
every(10) { puts "uptime: #{Time.now - t0}" }
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'modulation'
|
|
4
|
+
|
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
|
6
|
+
|
|
7
|
+
resource_count = 0
|
|
8
|
+
Pool = Polyphony::ResourcePool.new(limit: 3) do
|
|
9
|
+
:"resource#{resource_count += 1}"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def user(number)
|
|
13
|
+
loop do
|
|
14
|
+
move_on_after(0.2) do |scope|
|
|
15
|
+
scope.when_cancelled do
|
|
16
|
+
puts "#{number} (cancelled)"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Pool.acquire do |r|
|
|
20
|
+
scope.disable
|
|
21
|
+
puts "#{number} #{r.inspect} >"
|
|
22
|
+
sleep(0.4 + rand * 0.2)
|
|
23
|
+
puts "#{number} #{r.inspect} <"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
6.times do |x|
|
|
30
|
+
spawn { user(x) }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
t0 = Time.now
|
|
34
|
+
every(10) { puts "uptime: #{Time.now - t0}" }
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'modulation'
|
|
4
|
+
|
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
|
6
|
+
|
|
7
|
+
class Number
|
|
8
|
+
def initialize(id)
|
|
9
|
+
@id = id
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def greet(other)
|
|
13
|
+
puts "You are number #{other}, I am number #{@id}"
|
|
14
|
+
sleep(0.05 + rand * 0.2)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
resource_count = 0
|
|
19
|
+
Pool = Polyphony::ResourcePool.new(limit: 3) do
|
|
20
|
+
Number.new(resource_count += 1)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
async def meet(number)
|
|
24
|
+
loop do
|
|
25
|
+
Pool.greet(number)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
3.times { |x| spawn meet(x) }
|
|
30
|
+
|
|
31
|
+
t0 = Time.now
|
|
32
|
+
every(10) { puts "uptime: #{Time.now - t0}" }
|