polyphony 0.43.8
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 +7 -0
- data/.gitbook.yaml +4 -0
- data/.github/workflows/test.yml +29 -0
- data/.gitignore +59 -0
- data/.rubocop.yml +175 -0
- data/CHANGELOG.md +393 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +141 -0
- data/LICENSE +21 -0
- data/README.md +51 -0
- data/Rakefile +26 -0
- data/TODO.md +201 -0
- data/bin/polyphony-debug +87 -0
- data/docs/_config.yml +64 -0
- data/docs/_includes/head.html +40 -0
- data/docs/_includes/title.html +1 -0
- data/docs/_sass/custom/custom.scss +10 -0
- data/docs/_sass/overrides.scss +0 -0
- data/docs/_user-guide/all-about-timers.md +126 -0
- data/docs/_user-guide/index.md +9 -0
- data/docs/_user-guide/web-server.md +136 -0
- data/docs/api-reference/exception.md +27 -0
- data/docs/api-reference/fiber.md +425 -0
- data/docs/api-reference/index.md +9 -0
- data/docs/api-reference/io.md +36 -0
- data/docs/api-reference/object.md +99 -0
- data/docs/api-reference/polyphony-baseexception.md +33 -0
- data/docs/api-reference/polyphony-cancel.md +26 -0
- data/docs/api-reference/polyphony-moveon.md +24 -0
- data/docs/api-reference/polyphony-net.md +20 -0
- data/docs/api-reference/polyphony-process.md +28 -0
- data/docs/api-reference/polyphony-resourcepool.md +59 -0
- data/docs/api-reference/polyphony-restart.md +18 -0
- data/docs/api-reference/polyphony-terminate.md +18 -0
- data/docs/api-reference/polyphony-threadpool.md +67 -0
- data/docs/api-reference/polyphony-throttler.md +77 -0
- data/docs/api-reference/polyphony.md +36 -0
- data/docs/api-reference/thread.md +88 -0
- data/docs/assets/img/echo-fibers.svg +1 -0
- data/docs/assets/img/sleeping-fiber.svg +1 -0
- data/docs/faq.md +195 -0
- data/docs/favicon.ico +0 -0
- data/docs/getting-started/index.md +10 -0
- data/docs/getting-started/installing.md +34 -0
- data/docs/getting-started/overview.md +486 -0
- data/docs/getting-started/tutorial.md +359 -0
- data/docs/index.md +94 -0
- data/docs/main-concepts/concurrency.md +151 -0
- data/docs/main-concepts/design-principles.md +161 -0
- data/docs/main-concepts/exception-handling.md +291 -0
- data/docs/main-concepts/extending.md +89 -0
- data/docs/main-concepts/fiber-scheduling.md +197 -0
- data/docs/main-concepts/index.md +9 -0
- data/docs/polyphony-logo.png +0 -0
- data/examples/adapters/concurrent-ruby.rb +9 -0
- data/examples/adapters/pg_client.rb +36 -0
- data/examples/adapters/pg_notify.rb +35 -0
- data/examples/adapters/pg_pool.rb +43 -0
- data/examples/adapters/pg_transaction.rb +31 -0
- data/examples/adapters/redis_blpop.rb +12 -0
- data/examples/adapters/redis_channels.rb +122 -0
- data/examples/adapters/redis_client.rb +19 -0
- data/examples/adapters/redis_pubsub.rb +26 -0
- data/examples/adapters/redis_pubsub_perf.rb +68 -0
- data/examples/core/01-spinning-up-fibers.rb +18 -0
- data/examples/core/02-awaiting-fibers.rb +20 -0
- data/examples/core/03-interrupting.rb +39 -0
- data/examples/core/04-handling-signals.rb +19 -0
- data/examples/core/xx-agent.rb +102 -0
- data/examples/core/xx-at_exit.rb +29 -0
- data/examples/core/xx-caller.rb +12 -0
- data/examples/core/xx-channels.rb +45 -0
- data/examples/core/xx-daemon.rb +14 -0
- data/examples/core/xx-deadlock.rb +8 -0
- data/examples/core/xx-deferring-an-operation.rb +14 -0
- data/examples/core/xx-erlang-style-genserver.rb +81 -0
- data/examples/core/xx-exception-backtrace.rb +40 -0
- data/examples/core/xx-fork-cleanup.rb +22 -0
- data/examples/core/xx-fork-spin.rb +42 -0
- data/examples/core/xx-fork-terminate.rb +27 -0
- data/examples/core/xx-forking.rb +24 -0
- data/examples/core/xx-move_on.rb +23 -0
- data/examples/core/xx-pingpong.rb +18 -0
- data/examples/core/xx-queue-async.rb +120 -0
- data/examples/core/xx-readpartial.rb +18 -0
- data/examples/core/xx-recurrent-timer.rb +12 -0
- data/examples/core/xx-resource_delegate.rb +31 -0
- data/examples/core/xx-signals.rb +16 -0
- data/examples/core/xx-sleep-forever.rb +9 -0
- data/examples/core/xx-sleeping.rb +25 -0
- data/examples/core/xx-snooze-starve.rb +16 -0
- data/examples/core/xx-spin-fork.rb +49 -0
- data/examples/core/xx-spin_error_backtrace.rb +33 -0
- data/examples/core/xx-state-machine.rb +51 -0
- data/examples/core/xx-stop.rb +20 -0
- data/examples/core/xx-supervise-process.rb +30 -0
- data/examples/core/xx-supervisors.rb +21 -0
- data/examples/core/xx-thread-selector-sleep.rb +51 -0
- data/examples/core/xx-thread-selector-snooze.rb +46 -0
- data/examples/core/xx-thread-sleep.rb +17 -0
- data/examples/core/xx-thread-snooze.rb +34 -0
- data/examples/core/xx-thread_pool.rb +17 -0
- data/examples/core/xx-throttling.rb +18 -0
- data/examples/core/xx-timeout.rb +10 -0
- data/examples/core/xx-timer-gc.rb +17 -0
- data/examples/core/xx-trace.rb +79 -0
- data/examples/core/xx-using-a-mutex.rb +21 -0
- data/examples/core/xx-worker-thread.rb +30 -0
- data/examples/io/tunnel.rb +48 -0
- data/examples/io/xx-backticks.rb +11 -0
- data/examples/io/xx-echo_client.rb +25 -0
- data/examples/io/xx-echo_client_from_stdin.rb +21 -0
- data/examples/io/xx-echo_pipe.rb +16 -0
- data/examples/io/xx-echo_server.rb +17 -0
- data/examples/io/xx-echo_server_with_timeout.rb +34 -0
- data/examples/io/xx-echo_stdin.rb +14 -0
- data/examples/io/xx-happy-eyeballs.rb +36 -0
- data/examples/io/xx-httparty.rb +38 -0
- data/examples/io/xx-irb.rb +17 -0
- data/examples/io/xx-net-http.rb +15 -0
- data/examples/io/xx-open.rb +16 -0
- data/examples/io/xx-switch.rb +15 -0
- data/examples/io/xx-system.rb +11 -0
- data/examples/io/xx-tcpserver.rb +15 -0
- data/examples/io/xx-tcpsocket.rb +18 -0
- data/examples/io/xx-zip.rb +19 -0
- data/examples/performance/fiber_transfer.rb +47 -0
- data/examples/performance/fs_read.rb +38 -0
- data/examples/performance/mem-usage.rb +56 -0
- data/examples/performance/messaging.rb +29 -0
- data/examples/performance/multi_snooze.rb +33 -0
- data/examples/performance/snooze.rb +39 -0
- data/examples/performance/snooze_raw.rb +39 -0
- data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +74 -0
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +45 -0
- data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +58 -0
- data/examples/performance/thread-vs-fiber/threaded_server.rb +27 -0
- data/examples/performance/thread-vs-fiber/xx-httparty_multi.rb +36 -0
- data/examples/performance/thread-vs-fiber/xx-httparty_threaded.rb +29 -0
- data/examples/performance/thread_pool_perf.rb +63 -0
- data/examples/performance/xx-array.rb +11 -0
- data/examples/performance/xx-fiber-switch.rb +9 -0
- data/examples/performance/xx-snooze.rb +15 -0
- data/examples/xx-spin.rb +32 -0
- data/ext/libev/Changes +548 -0
- data/ext/libev/LICENSE +37 -0
- data/ext/libev/README +59 -0
- data/ext/libev/README.embed +3 -0
- data/ext/libev/ev.c +5279 -0
- data/ext/libev/ev.h +856 -0
- data/ext/libev/ev_epoll.c +296 -0
- data/ext/libev/ev_kqueue.c +224 -0
- data/ext/libev/ev_linuxaio.c +642 -0
- data/ext/libev/ev_poll.c +156 -0
- data/ext/libev/ev_port.c +192 -0
- data/ext/libev/ev_select.c +316 -0
- data/ext/libev/ev_vars.h +215 -0
- data/ext/libev/ev_win32.c +162 -0
- data/ext/libev/ev_wrap.h +216 -0
- data/ext/libev/test_libev_win32.c +123 -0
- data/ext/polyphony/extconf.rb +20 -0
- data/ext/polyphony/fiber.c +109 -0
- data/ext/polyphony/libev.c +2 -0
- data/ext/polyphony/libev.h +9 -0
- data/ext/polyphony/libev_agent.c +882 -0
- data/ext/polyphony/polyphony.c +71 -0
- data/ext/polyphony/polyphony.h +97 -0
- data/ext/polyphony/polyphony_ext.c +21 -0
- data/ext/polyphony/queue.c +168 -0
- data/ext/polyphony/ring_buffer.c +96 -0
- data/ext/polyphony/ring_buffer.h +28 -0
- data/ext/polyphony/thread.c +208 -0
- data/ext/polyphony/tracing.c +11 -0
- data/lib/polyphony.rb +136 -0
- data/lib/polyphony/adapters/fs.rb +19 -0
- data/lib/polyphony/adapters/irb.rb +52 -0
- data/lib/polyphony/adapters/postgres.rb +110 -0
- data/lib/polyphony/adapters/process.rb +33 -0
- data/lib/polyphony/adapters/redis.rb +67 -0
- data/lib/polyphony/adapters/trace.rb +138 -0
- data/lib/polyphony/core/channel.rb +46 -0
- data/lib/polyphony/core/exceptions.rb +36 -0
- data/lib/polyphony/core/global_api.rb +124 -0
- data/lib/polyphony/core/resource_pool.rb +117 -0
- data/lib/polyphony/core/sync.rb +21 -0
- data/lib/polyphony/core/thread_pool.rb +64 -0
- data/lib/polyphony/core/throttler.rb +41 -0
- data/lib/polyphony/event.rb +17 -0
- data/lib/polyphony/extensions/core.rb +174 -0
- data/lib/polyphony/extensions/fiber.rb +379 -0
- data/lib/polyphony/extensions/io.rb +221 -0
- data/lib/polyphony/extensions/openssl.rb +81 -0
- data/lib/polyphony/extensions/socket.rb +150 -0
- data/lib/polyphony/extensions/thread.rb +108 -0
- data/lib/polyphony/net.rb +77 -0
- data/lib/polyphony/version.rb +5 -0
- data/polyphony.gemspec +40 -0
- data/test/coverage.rb +54 -0
- data/test/eg.rb +27 -0
- data/test/helper.rb +56 -0
- data/test/q.rb +24 -0
- data/test/run.rb +5 -0
- data/test/stress.rb +25 -0
- data/test/test_agent.rb +130 -0
- data/test/test_event.rb +59 -0
- data/test/test_ext.rb +196 -0
- data/test/test_fiber.rb +988 -0
- data/test/test_global_api.rb +352 -0
- data/test/test_io.rb +249 -0
- data/test/test_kernel.rb +57 -0
- data/test/test_process_supervision.rb +46 -0
- data/test/test_queue.rb +112 -0
- data/test/test_resource_pool.rb +138 -0
- data/test/test_signal.rb +100 -0
- data/test/test_socket.rb +34 -0
- data/test/test_supervise.rb +103 -0
- data/test/test_thread.rb +170 -0
- data/test/test_thread_pool.rb +101 -0
- data/test/test_throttler.rb +50 -0
- data/test/test_trace.rb +68 -0
- metadata +482 -0
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony/adapters/redis'
|
5
|
+
# require 'redis'
|
6
|
+
|
7
|
+
redis = Redis.new(host: ENV['REDISHOST'] || 'localhost')
|
8
|
+
|
9
|
+
redis.lpush("queue_key", "omgvalue")
|
10
|
+
puts "len: #{redis.llen("queue_key")}"
|
11
|
+
result = redis.blpop("queue_key")
|
12
|
+
puts result.inspect
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony/adapters/redis'
|
5
|
+
|
6
|
+
class RedisChannel < Polyphony::Channel
|
7
|
+
def self.publish_connection
|
8
|
+
@publish_connection ||= Redis.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.subscribe_connection
|
12
|
+
@subscribe_connection ||= Redis.new
|
13
|
+
end
|
14
|
+
|
15
|
+
CHANNEL_MASTER_TOPIC = 'channel_master'
|
16
|
+
|
17
|
+
def self.start_monitor
|
18
|
+
@channels = {}
|
19
|
+
@monitor = spin do
|
20
|
+
subscribe_connection.subscribe(CHANNEL_MASTER_TOPIC) do |on|
|
21
|
+
on.message do |topic, message|
|
22
|
+
message = Marshal.load(message)
|
23
|
+
topic == if CHANNEL_MASTER_TOPIC
|
24
|
+
handle_master_message(message)
|
25
|
+
else
|
26
|
+
handle_channel_message(topic, message)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.stop_monitor
|
34
|
+
@monitor&.interrupt
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.handle_master_message(message)
|
38
|
+
case message[:kind]
|
39
|
+
when :subscribe
|
40
|
+
subscribe_connection.subscribe(message[:topic])
|
41
|
+
when :unsubscribe
|
42
|
+
subscribe_connection.unsubscribe(message[:topic])
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.handle_channel_message(topic, message)
|
47
|
+
channel = @channels[topic]
|
48
|
+
channel&.did_receive(message)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.watch(channel)
|
52
|
+
@channels[channel.topic] = channel
|
53
|
+
spin do
|
54
|
+
publish_connection.publish(CHANNEL_MASTER_TOPIC, Marshal.dump(
|
55
|
+
kind: :subscribe,
|
56
|
+
topic: channel.topic
|
57
|
+
))
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.unwatch(channel)
|
62
|
+
@channels.delete(channel.topic)
|
63
|
+
spin do
|
64
|
+
publish_connection.publish(CHANNEL_MASTER_TOPIC, Marshal.dump(
|
65
|
+
kind: :unsubscribe,
|
66
|
+
topic: channel.topic
|
67
|
+
))
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.channel_topic(channel)
|
72
|
+
"channel_#{channel.object_id}"
|
73
|
+
end
|
74
|
+
|
75
|
+
attr_reader :topic
|
76
|
+
|
77
|
+
def initialize(topic)
|
78
|
+
@topic = topic
|
79
|
+
@waiting_queue = []
|
80
|
+
RedisChannel.watch(self)
|
81
|
+
end
|
82
|
+
|
83
|
+
def close
|
84
|
+
super
|
85
|
+
RedisChannel.unwatch(self)
|
86
|
+
end
|
87
|
+
|
88
|
+
def <<(o)
|
89
|
+
RedisChannel.publish_connection.publish(@topic, Marshal.dump(o))
|
90
|
+
end
|
91
|
+
|
92
|
+
def did_receive(o)
|
93
|
+
@waiting_queue.shift&.schedule(o)
|
94
|
+
end
|
95
|
+
|
96
|
+
def receive
|
97
|
+
@waiting_queue << Fiber.current
|
98
|
+
suspend
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
RedisChannel.start_monitor
|
103
|
+
channel = RedisChannel.new('channel1')
|
104
|
+
|
105
|
+
spin do
|
106
|
+
loop do
|
107
|
+
message = channel.receive
|
108
|
+
puts "got message: #{message}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
spin do
|
113
|
+
move_on_after(3) do
|
114
|
+
throttled_loop(1) do
|
115
|
+
channel << Time.now
|
116
|
+
end
|
117
|
+
end
|
118
|
+
channel.close
|
119
|
+
RedisChannel.stop_monitor
|
120
|
+
end
|
121
|
+
|
122
|
+
suspend
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony/adapters/redis'
|
5
|
+
|
6
|
+
redis = Redis.new
|
7
|
+
|
8
|
+
X = 10
|
9
|
+
|
10
|
+
t0 = Time.now
|
11
|
+
X.times { redis.get('abc') }
|
12
|
+
puts "get rate: #{X / (Time.now - t0)} reqs/s"
|
13
|
+
|
14
|
+
puts "abc = #{redis.get('abc')}"
|
15
|
+
|
16
|
+
puts 'updating value...'
|
17
|
+
redis.set('abc', Time.now.to_s)
|
18
|
+
|
19
|
+
puts "abc = #{redis.get('abc')}"
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony/adapters/redis'
|
5
|
+
|
6
|
+
spin do
|
7
|
+
redis = Redis.new
|
8
|
+
redis.subscribe('redis-channel') do |on|
|
9
|
+
on.message do |channel, message|
|
10
|
+
puts "##{channel}: #{message}"
|
11
|
+
redis.unsubscribe if message == 'exit'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
spin do
|
17
|
+
redis = Redis.new
|
18
|
+
move_on_after(3) do
|
19
|
+
throttled_loop(1) do
|
20
|
+
redis.publish('redis-channel', Time.now)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
redis.publish('redis-channel', 'exit')
|
24
|
+
end
|
25
|
+
|
26
|
+
suspend
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony/adapters/redis'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
X_SESSIONS = 1000
|
8
|
+
X_NODES = 10_000
|
9
|
+
X_SUBSCRIPTIONS_PER_SESSION = 100
|
10
|
+
|
11
|
+
$sessions = []
|
12
|
+
X_SESSIONS.times do
|
13
|
+
$sessions << {
|
14
|
+
subscriptions: X_SUBSCRIPTIONS_PER_SESSION.times.map do
|
15
|
+
"node#{rand(X_NODES)}"
|
16
|
+
end.uniq
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
spin do
|
21
|
+
redis = Redis.new
|
22
|
+
redis.subscribe('events') do |on|
|
23
|
+
on.message do |_, message|
|
24
|
+
distribute_event(JSON.parse(message, symbolize_names: true))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
$update_count = 0
|
30
|
+
|
31
|
+
def distribute_event(event)
|
32
|
+
$update_count += 1
|
33
|
+
# t0 = Time.now
|
34
|
+
count = 0
|
35
|
+
$sessions.each do |s|
|
36
|
+
count += 1 if s[:subscriptions].include?(event[:path])
|
37
|
+
end
|
38
|
+
# elapsed = Time.now - t0
|
39
|
+
# rate = X_SESSIONS / elapsed
|
40
|
+
# puts "elapsed: #{elapsed} (#{rate}/s)" if $update_count % 100 == 0
|
41
|
+
end
|
42
|
+
|
43
|
+
spin do
|
44
|
+
redis = Redis.new
|
45
|
+
throttled_loop(1000) do
|
46
|
+
redis.publish('events', { path: "node#{rand(X_NODES)}" }.to_json)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
spin do
|
51
|
+
last_count = 0
|
52
|
+
last_stamp = Time.now
|
53
|
+
throttled_loop(1) do
|
54
|
+
now = Time.now
|
55
|
+
elapsed = now - last_stamp
|
56
|
+
delta = $update_count - last_count
|
57
|
+
puts "update rate: #{delta.to_f / elapsed}"
|
58
|
+
last_stamp = now
|
59
|
+
last_count = $update_count
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
trap(:int) do
|
64
|
+
puts 'bye...'
|
65
|
+
exit!
|
66
|
+
end
|
67
|
+
|
68
|
+
suspend
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
|
5
|
+
require 'polyphony'
|
6
|
+
|
7
|
+
def nap(tag, t)
|
8
|
+
puts "#{Time.now} #{tag} napping for #{t} seconds..."
|
9
|
+
sleep t
|
10
|
+
puts "#{Time.now} #{tag} done napping"
|
11
|
+
end
|
12
|
+
|
13
|
+
# We launch two concurrent fibers, each sleeping for the given duration.
|
14
|
+
spin { nap(:a, 1) }
|
15
|
+
spin { nap(:b, 2) }
|
16
|
+
|
17
|
+
# Calling suspend will block until all child fibers have terminated
|
18
|
+
suspend
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
sleeper = spin do
|
7
|
+
puts 'going to sleep'
|
8
|
+
sleep 1
|
9
|
+
puts 'woke up'
|
10
|
+
end
|
11
|
+
|
12
|
+
# One way to synchronize fibers is by using `Fiber#await`, which blocks
|
13
|
+
# until the fiber has finished running or has been interrupted.
|
14
|
+
waiter = spin do
|
15
|
+
puts 'waiting for fiber to terminate'
|
16
|
+
sleeper.await
|
17
|
+
puts 'done waiting'
|
18
|
+
end
|
19
|
+
|
20
|
+
waiter.await
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
# Let's see how a long-running blocking operation can be interrupted. Polyphony
|
7
|
+
# provides several APIs for interrupting an ongoing operation, and distinguishes
|
8
|
+
# between two different types of interruptions: *cancel* and *move on*. A
|
9
|
+
# *cancel* will interrupt an ongoing operation and raise an exception. A *move
|
10
|
+
# on* will interrupt an ongoing operation without raising an exception,
|
11
|
+
# optionally returning an arbitrary value as the result of that operation.
|
12
|
+
|
13
|
+
def nap(tag, t)
|
14
|
+
puts "#{Time.now} #{tag} napping for #{t} seconds..."
|
15
|
+
sleep t
|
16
|
+
ensure
|
17
|
+
puts "#{Time.now} #{tag} done napping"
|
18
|
+
end
|
19
|
+
|
20
|
+
# The Kernel#cancel_after interrupts a blocking operation by raising a
|
21
|
+
# Polyphony::Cancel exception after the given timeout. If not rescued, the
|
22
|
+
# exception is propagated up the fiber hierarchy
|
23
|
+
spin do
|
24
|
+
# cancel after 1 second
|
25
|
+
cancel_after(1) { nap(:cancel, 2) }
|
26
|
+
rescue Polyphony::Cancel => e
|
27
|
+
puts "got exception: #{e}"
|
28
|
+
end
|
29
|
+
|
30
|
+
# The Kernel#move_on_after interrupts a blocking operation by raising a
|
31
|
+
# Polyphony::MoveOn exception, which is silently swallowed by the fiber
|
32
|
+
spin do
|
33
|
+
# move on after 1 second
|
34
|
+
move_on_after(1) do
|
35
|
+
nap(:move_on, 2)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
suspend
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
# trap('TERM') do
|
7
|
+
# Polyphony.emit_signal_exception(::SystemExit)
|
8
|
+
# end
|
9
|
+
|
10
|
+
# trap('INT') do
|
11
|
+
# Polyphony.emit_signal_exception(::Interrupt)
|
12
|
+
# end
|
13
|
+
|
14
|
+
puts "go to sleep"
|
15
|
+
begin
|
16
|
+
sleep
|
17
|
+
ensure
|
18
|
+
puts "done sleeping"
|
19
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
Exception.__disable_sanitized_backtrace__ = true
|
7
|
+
|
8
|
+
class Test
|
9
|
+
def test_sleep
|
10
|
+
puts "going to sleep"
|
11
|
+
sleep 1
|
12
|
+
puts "done sleeping"
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_spin
|
16
|
+
spin {
|
17
|
+
10.times {
|
18
|
+
STDOUT << '.'
|
19
|
+
sleep 0.1
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
puts "going to sleep\n"
|
24
|
+
sleep 1
|
25
|
+
puts 'woke up'
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_file
|
29
|
+
f = File.open(__FILE__, 'r')
|
30
|
+
puts Thread.current.agent.read(f, +'', 10000, true)
|
31
|
+
|
32
|
+
Thread.current.agent.write(STDOUT, "Write something: ")
|
33
|
+
str = +''
|
34
|
+
Thread.current.agent.read(STDIN, str, 5, false)
|
35
|
+
puts str
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_fork
|
39
|
+
pid = fork do
|
40
|
+
Thread.current.agent.post_fork
|
41
|
+
puts 'child going to sleep'
|
42
|
+
sleep 1
|
43
|
+
puts 'child done sleeping'
|
44
|
+
exit(42)
|
45
|
+
end
|
46
|
+
|
47
|
+
puts "Waiting for pid #{pid}"
|
48
|
+
result = Thread.current.agent.waitpid(pid)
|
49
|
+
puts "Done waiting"
|
50
|
+
p result
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_async
|
54
|
+
async = Polyphony::Event.new
|
55
|
+
|
56
|
+
spin {
|
57
|
+
puts "signaller starting"
|
58
|
+
sleep 1
|
59
|
+
puts "signal"
|
60
|
+
async.signal(:foo)
|
61
|
+
}
|
62
|
+
|
63
|
+
puts "awaiting event"
|
64
|
+
p async.await
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_queue
|
68
|
+
q = Gyro::Queue.new
|
69
|
+
spin {
|
70
|
+
10.times {
|
71
|
+
q << Time.now.to_f
|
72
|
+
sleep 0.2
|
73
|
+
}
|
74
|
+
q << :STOP
|
75
|
+
}
|
76
|
+
|
77
|
+
loop do
|
78
|
+
value = q.shift
|
79
|
+
break if value == :STOP
|
80
|
+
|
81
|
+
p value
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_thread
|
86
|
+
t = Thread.new do
|
87
|
+
puts "thread going to sleep"
|
88
|
+
sleep 0.2
|
89
|
+
puts "thread done sleeping"
|
90
|
+
end
|
91
|
+
|
92
|
+
t.await
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
t = Test.new
|
97
|
+
|
98
|
+
t.methods.select { |m| m =~ /^test_/ }.each do |m|
|
99
|
+
puts '*' * 40
|
100
|
+
puts m
|
101
|
+
t.send(m)
|
102
|
+
end
|