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.
Files changed (221) hide show
  1. checksums.yaml +7 -0
  2. data/.gitbook.yaml +4 -0
  3. data/.github/workflows/test.yml +29 -0
  4. data/.gitignore +59 -0
  5. data/.rubocop.yml +175 -0
  6. data/CHANGELOG.md +393 -0
  7. data/Gemfile +3 -0
  8. data/Gemfile.lock +141 -0
  9. data/LICENSE +21 -0
  10. data/README.md +51 -0
  11. data/Rakefile +26 -0
  12. data/TODO.md +201 -0
  13. data/bin/polyphony-debug +87 -0
  14. data/docs/_config.yml +64 -0
  15. data/docs/_includes/head.html +40 -0
  16. data/docs/_includes/title.html +1 -0
  17. data/docs/_sass/custom/custom.scss +10 -0
  18. data/docs/_sass/overrides.scss +0 -0
  19. data/docs/_user-guide/all-about-timers.md +126 -0
  20. data/docs/_user-guide/index.md +9 -0
  21. data/docs/_user-guide/web-server.md +136 -0
  22. data/docs/api-reference/exception.md +27 -0
  23. data/docs/api-reference/fiber.md +425 -0
  24. data/docs/api-reference/index.md +9 -0
  25. data/docs/api-reference/io.md +36 -0
  26. data/docs/api-reference/object.md +99 -0
  27. data/docs/api-reference/polyphony-baseexception.md +33 -0
  28. data/docs/api-reference/polyphony-cancel.md +26 -0
  29. data/docs/api-reference/polyphony-moveon.md +24 -0
  30. data/docs/api-reference/polyphony-net.md +20 -0
  31. data/docs/api-reference/polyphony-process.md +28 -0
  32. data/docs/api-reference/polyphony-resourcepool.md +59 -0
  33. data/docs/api-reference/polyphony-restart.md +18 -0
  34. data/docs/api-reference/polyphony-terminate.md +18 -0
  35. data/docs/api-reference/polyphony-threadpool.md +67 -0
  36. data/docs/api-reference/polyphony-throttler.md +77 -0
  37. data/docs/api-reference/polyphony.md +36 -0
  38. data/docs/api-reference/thread.md +88 -0
  39. data/docs/assets/img/echo-fibers.svg +1 -0
  40. data/docs/assets/img/sleeping-fiber.svg +1 -0
  41. data/docs/faq.md +195 -0
  42. data/docs/favicon.ico +0 -0
  43. data/docs/getting-started/index.md +10 -0
  44. data/docs/getting-started/installing.md +34 -0
  45. data/docs/getting-started/overview.md +486 -0
  46. data/docs/getting-started/tutorial.md +359 -0
  47. data/docs/index.md +94 -0
  48. data/docs/main-concepts/concurrency.md +151 -0
  49. data/docs/main-concepts/design-principles.md +161 -0
  50. data/docs/main-concepts/exception-handling.md +291 -0
  51. data/docs/main-concepts/extending.md +89 -0
  52. data/docs/main-concepts/fiber-scheduling.md +197 -0
  53. data/docs/main-concepts/index.md +9 -0
  54. data/docs/polyphony-logo.png +0 -0
  55. data/examples/adapters/concurrent-ruby.rb +9 -0
  56. data/examples/adapters/pg_client.rb +36 -0
  57. data/examples/adapters/pg_notify.rb +35 -0
  58. data/examples/adapters/pg_pool.rb +43 -0
  59. data/examples/adapters/pg_transaction.rb +31 -0
  60. data/examples/adapters/redis_blpop.rb +12 -0
  61. data/examples/adapters/redis_channels.rb +122 -0
  62. data/examples/adapters/redis_client.rb +19 -0
  63. data/examples/adapters/redis_pubsub.rb +26 -0
  64. data/examples/adapters/redis_pubsub_perf.rb +68 -0
  65. data/examples/core/01-spinning-up-fibers.rb +18 -0
  66. data/examples/core/02-awaiting-fibers.rb +20 -0
  67. data/examples/core/03-interrupting.rb +39 -0
  68. data/examples/core/04-handling-signals.rb +19 -0
  69. data/examples/core/xx-agent.rb +102 -0
  70. data/examples/core/xx-at_exit.rb +29 -0
  71. data/examples/core/xx-caller.rb +12 -0
  72. data/examples/core/xx-channels.rb +45 -0
  73. data/examples/core/xx-daemon.rb +14 -0
  74. data/examples/core/xx-deadlock.rb +8 -0
  75. data/examples/core/xx-deferring-an-operation.rb +14 -0
  76. data/examples/core/xx-erlang-style-genserver.rb +81 -0
  77. data/examples/core/xx-exception-backtrace.rb +40 -0
  78. data/examples/core/xx-fork-cleanup.rb +22 -0
  79. data/examples/core/xx-fork-spin.rb +42 -0
  80. data/examples/core/xx-fork-terminate.rb +27 -0
  81. data/examples/core/xx-forking.rb +24 -0
  82. data/examples/core/xx-move_on.rb +23 -0
  83. data/examples/core/xx-pingpong.rb +18 -0
  84. data/examples/core/xx-queue-async.rb +120 -0
  85. data/examples/core/xx-readpartial.rb +18 -0
  86. data/examples/core/xx-recurrent-timer.rb +12 -0
  87. data/examples/core/xx-resource_delegate.rb +31 -0
  88. data/examples/core/xx-signals.rb +16 -0
  89. data/examples/core/xx-sleep-forever.rb +9 -0
  90. data/examples/core/xx-sleeping.rb +25 -0
  91. data/examples/core/xx-snooze-starve.rb +16 -0
  92. data/examples/core/xx-spin-fork.rb +49 -0
  93. data/examples/core/xx-spin_error_backtrace.rb +33 -0
  94. data/examples/core/xx-state-machine.rb +51 -0
  95. data/examples/core/xx-stop.rb +20 -0
  96. data/examples/core/xx-supervise-process.rb +30 -0
  97. data/examples/core/xx-supervisors.rb +21 -0
  98. data/examples/core/xx-thread-selector-sleep.rb +51 -0
  99. data/examples/core/xx-thread-selector-snooze.rb +46 -0
  100. data/examples/core/xx-thread-sleep.rb +17 -0
  101. data/examples/core/xx-thread-snooze.rb +34 -0
  102. data/examples/core/xx-thread_pool.rb +17 -0
  103. data/examples/core/xx-throttling.rb +18 -0
  104. data/examples/core/xx-timeout.rb +10 -0
  105. data/examples/core/xx-timer-gc.rb +17 -0
  106. data/examples/core/xx-trace.rb +79 -0
  107. data/examples/core/xx-using-a-mutex.rb +21 -0
  108. data/examples/core/xx-worker-thread.rb +30 -0
  109. data/examples/io/tunnel.rb +48 -0
  110. data/examples/io/xx-backticks.rb +11 -0
  111. data/examples/io/xx-echo_client.rb +25 -0
  112. data/examples/io/xx-echo_client_from_stdin.rb +21 -0
  113. data/examples/io/xx-echo_pipe.rb +16 -0
  114. data/examples/io/xx-echo_server.rb +17 -0
  115. data/examples/io/xx-echo_server_with_timeout.rb +34 -0
  116. data/examples/io/xx-echo_stdin.rb +14 -0
  117. data/examples/io/xx-happy-eyeballs.rb +36 -0
  118. data/examples/io/xx-httparty.rb +38 -0
  119. data/examples/io/xx-irb.rb +17 -0
  120. data/examples/io/xx-net-http.rb +15 -0
  121. data/examples/io/xx-open.rb +16 -0
  122. data/examples/io/xx-switch.rb +15 -0
  123. data/examples/io/xx-system.rb +11 -0
  124. data/examples/io/xx-tcpserver.rb +15 -0
  125. data/examples/io/xx-tcpsocket.rb +18 -0
  126. data/examples/io/xx-zip.rb +19 -0
  127. data/examples/performance/fiber_transfer.rb +47 -0
  128. data/examples/performance/fs_read.rb +38 -0
  129. data/examples/performance/mem-usage.rb +56 -0
  130. data/examples/performance/messaging.rb +29 -0
  131. data/examples/performance/multi_snooze.rb +33 -0
  132. data/examples/performance/snooze.rb +39 -0
  133. data/examples/performance/snooze_raw.rb +39 -0
  134. data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +74 -0
  135. data/examples/performance/thread-vs-fiber/polyphony_server.rb +45 -0
  136. data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +58 -0
  137. data/examples/performance/thread-vs-fiber/threaded_server.rb +27 -0
  138. data/examples/performance/thread-vs-fiber/xx-httparty_multi.rb +36 -0
  139. data/examples/performance/thread-vs-fiber/xx-httparty_threaded.rb +29 -0
  140. data/examples/performance/thread_pool_perf.rb +63 -0
  141. data/examples/performance/xx-array.rb +11 -0
  142. data/examples/performance/xx-fiber-switch.rb +9 -0
  143. data/examples/performance/xx-snooze.rb +15 -0
  144. data/examples/xx-spin.rb +32 -0
  145. data/ext/libev/Changes +548 -0
  146. data/ext/libev/LICENSE +37 -0
  147. data/ext/libev/README +59 -0
  148. data/ext/libev/README.embed +3 -0
  149. data/ext/libev/ev.c +5279 -0
  150. data/ext/libev/ev.h +856 -0
  151. data/ext/libev/ev_epoll.c +296 -0
  152. data/ext/libev/ev_kqueue.c +224 -0
  153. data/ext/libev/ev_linuxaio.c +642 -0
  154. data/ext/libev/ev_poll.c +156 -0
  155. data/ext/libev/ev_port.c +192 -0
  156. data/ext/libev/ev_select.c +316 -0
  157. data/ext/libev/ev_vars.h +215 -0
  158. data/ext/libev/ev_win32.c +162 -0
  159. data/ext/libev/ev_wrap.h +216 -0
  160. data/ext/libev/test_libev_win32.c +123 -0
  161. data/ext/polyphony/extconf.rb +20 -0
  162. data/ext/polyphony/fiber.c +109 -0
  163. data/ext/polyphony/libev.c +2 -0
  164. data/ext/polyphony/libev.h +9 -0
  165. data/ext/polyphony/libev_agent.c +882 -0
  166. data/ext/polyphony/polyphony.c +71 -0
  167. data/ext/polyphony/polyphony.h +97 -0
  168. data/ext/polyphony/polyphony_ext.c +21 -0
  169. data/ext/polyphony/queue.c +168 -0
  170. data/ext/polyphony/ring_buffer.c +96 -0
  171. data/ext/polyphony/ring_buffer.h +28 -0
  172. data/ext/polyphony/thread.c +208 -0
  173. data/ext/polyphony/tracing.c +11 -0
  174. data/lib/polyphony.rb +136 -0
  175. data/lib/polyphony/adapters/fs.rb +19 -0
  176. data/lib/polyphony/adapters/irb.rb +52 -0
  177. data/lib/polyphony/adapters/postgres.rb +110 -0
  178. data/lib/polyphony/adapters/process.rb +33 -0
  179. data/lib/polyphony/adapters/redis.rb +67 -0
  180. data/lib/polyphony/adapters/trace.rb +138 -0
  181. data/lib/polyphony/core/channel.rb +46 -0
  182. data/lib/polyphony/core/exceptions.rb +36 -0
  183. data/lib/polyphony/core/global_api.rb +124 -0
  184. data/lib/polyphony/core/resource_pool.rb +117 -0
  185. data/lib/polyphony/core/sync.rb +21 -0
  186. data/lib/polyphony/core/thread_pool.rb +64 -0
  187. data/lib/polyphony/core/throttler.rb +41 -0
  188. data/lib/polyphony/event.rb +17 -0
  189. data/lib/polyphony/extensions/core.rb +174 -0
  190. data/lib/polyphony/extensions/fiber.rb +379 -0
  191. data/lib/polyphony/extensions/io.rb +221 -0
  192. data/lib/polyphony/extensions/openssl.rb +81 -0
  193. data/lib/polyphony/extensions/socket.rb +150 -0
  194. data/lib/polyphony/extensions/thread.rb +108 -0
  195. data/lib/polyphony/net.rb +77 -0
  196. data/lib/polyphony/version.rb +5 -0
  197. data/polyphony.gemspec +40 -0
  198. data/test/coverage.rb +54 -0
  199. data/test/eg.rb +27 -0
  200. data/test/helper.rb +56 -0
  201. data/test/q.rb +24 -0
  202. data/test/run.rb +5 -0
  203. data/test/stress.rb +25 -0
  204. data/test/test_agent.rb +130 -0
  205. data/test/test_event.rb +59 -0
  206. data/test/test_ext.rb +196 -0
  207. data/test/test_fiber.rb +988 -0
  208. data/test/test_global_api.rb +352 -0
  209. data/test/test_io.rb +249 -0
  210. data/test/test_kernel.rb +57 -0
  211. data/test/test_process_supervision.rb +46 -0
  212. data/test/test_queue.rb +112 -0
  213. data/test/test_resource_pool.rb +138 -0
  214. data/test/test_signal.rb +100 -0
  215. data/test/test_socket.rb +34 -0
  216. data/test/test_supervise.rb +103 -0
  217. data/test/test_thread.rb +170 -0
  218. data/test/test_thread_pool.rb +101 -0
  219. data/test/test_throttler.rb +50 -0
  220. data/test/test_trace.rb +68 -0
  221. metadata +482 -0
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ Exception.__disable_sanitized_backtrace__ = true
7
+
8
+ child_pid = Polyphony.fork do
9
+ at_exit do
10
+ puts "at_exit"
11
+ f = spin { sleep 10 }
12
+ trap('SIGINT') { f.stop }
13
+ f.await
14
+ end
15
+
16
+ f1 = spin { sleep 100 }
17
+
18
+ puts "pid: #{Process.pid}"
19
+
20
+ pid = Process.pid
21
+
22
+ f1.join
23
+ end
24
+
25
+ sleep 0.1
26
+ Process.kill('INT', child_pid)
27
+ sleep 0.1
28
+ Process.kill('INT', child_pid)
29
+ Process.wait(child_pid)
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ spin {
7
+ spin {
8
+ spin {
9
+ pp Fiber.current.caller
10
+ }.await
11
+ }.await
12
+ }.await
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ def echo(cin, cout)
7
+ puts 'start echoer'
8
+ while (msg = cin.receive)
9
+ cout << "you said: #{msg}"
10
+ end
11
+ ensure
12
+ puts 'echoer stopped'
13
+ end
14
+
15
+ chan1, chan2 = 2.times.map { Polyphony::Channel.new }
16
+
17
+ spin { echo(chan1, chan2) }
18
+
19
+ spin do
20
+ puts 'start receiver'
21
+ while (msg = chan2.receive)
22
+ puts msg
23
+ $main.resume if msg =~ /world/
24
+ end
25
+ ensure
26
+ puts 'receiver stopped'
27
+ end
28
+
29
+ $main = spin do
30
+ puts 'start main'
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
44
+
45
+ suspend
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ Exception.__disable_sanitized_backtrace__ = true
7
+
8
+ puts "pid: #{Process.pid}"
9
+
10
+ Process.daemon(true, true)
11
+
12
+ Polyphony::ThreadPool.process do
13
+ puts "Hello world from pid #{Process.pid}"
14
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ spin { sleep }
7
+
8
+ sleep
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ spin do
7
+ puts 'two'
8
+ spin { puts 'four' }
9
+ puts 'three'
10
+ end
11
+
12
+ puts 'one'
13
+
14
+ suspend
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ class GenServer
7
+ def self.start(receiver, *args)
8
+ fiber = spin do
9
+ state = receiver.initial_state(*args)
10
+ loop do
11
+ msg = receive
12
+ reply, state = receiver.send(msg[:method], state, *msg[:args])
13
+ msg[:from] << reply unless reply == :noreply
14
+ end
15
+ end
16
+ build_api(fiber, receiver)
17
+ snooze
18
+ fiber
19
+ end
20
+
21
+ def self.build_api(fiber, receiver)
22
+ receiver.methods(false).each do |m|
23
+ if m =~ /!$/
24
+ fiber.define_singleton_method(m) do |*args|
25
+ GenServer.cast(fiber, m, *args)
26
+ end
27
+ else
28
+ fiber.define_singleton_method(m) do |*args|
29
+ GenServer.call(fiber, m, *args)
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ def self.cast(process, method, *args)
36
+ process << {
37
+ from: Fiber.current,
38
+ method: method,
39
+ args: args
40
+ }
41
+ end
42
+
43
+ def self.call(process, method, *args)
44
+ process << {
45
+ from: Fiber.current,
46
+ method: method,
47
+ args: args
48
+ }
49
+ receive
50
+ end
51
+ end
52
+
53
+ module Map
54
+ def self.initial_state(hash = {})
55
+ hash
56
+ end
57
+
58
+ def self.get(state, key)
59
+ [state[key], state]
60
+ end
61
+
62
+ def self.put!(state, key, value)
63
+ state[key] = value
64
+ [:noreply, state]
65
+ end
66
+ end
67
+
68
+ map_server = GenServer.start(Map, {foo: :bar})
69
+
70
+ puts 'getting value from map server'
71
+ v = map_server.get(:foo)
72
+ puts "value: #{v.inspect}"
73
+
74
+ puts 'putting value in map server'
75
+ map_server.put!(:foo, :baz)
76
+
77
+ puts 'getting value from map server'
78
+ v = map_server.get(:foo)
79
+ puts "value: #{v.inspect}"
80
+
81
+ map_server.stop
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+
5
+ class E < Exception
6
+ def initialize(msg)
7
+ super
8
+ # set_backtrace(caller)
9
+ end
10
+
11
+ alias_method :orig_backtrace, :backtrace
12
+ def backtrace
13
+ b = orig_backtrace
14
+ p [:backtrace, b, caller]
15
+ b
16
+ end
17
+ end
18
+
19
+ def e1
20
+ e2
21
+ end
22
+
23
+ def e2
24
+ E.new('foo')
25
+ end
26
+
27
+ def e3
28
+ raise E, 'bar'
29
+ end
30
+
31
+ e = e1
32
+ p e
33
+ puts e.backtrace&.join("\n")
34
+
35
+ begin
36
+ e3
37
+ rescue Exception => e
38
+ p e
39
+ puts e.backtrace.join("\n")
40
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ Exception.__disable_sanitized_backtrace__ = true
7
+
8
+ t = Thread.new do
9
+ async = Gyro::Async.new
10
+ spin { async.await }
11
+ sleep 100
12
+ end
13
+
14
+ sleep 0.5
15
+
16
+ Polyphony.fork do
17
+ puts "forked #{Process.pid}"
18
+ sleep 1
19
+ puts "done sleeping"
20
+ end
21
+
22
+ sleep 50
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ Exception.__disable_sanitized_backtrace__ = true
7
+
8
+ puts "Parent pid: #{Process.pid}"
9
+
10
+ i, o = IO.pipe
11
+
12
+ pid = Polyphony.fork do
13
+ puts "Child pid: #{Process.pid}"
14
+ i.close
15
+ spin do
16
+ spin do
17
+ p :sleep
18
+ sleep 1
19
+ rescue ::Interrupt => e
20
+ p 1
21
+ # the signal should be raised only in the main fiber
22
+ o.puts "1-interrupt"
23
+ end.await
24
+ rescue Polyphony::Terminate
25
+ puts "terminate!"
26
+ end.await
27
+ rescue ::Interrupt => e
28
+ p 2
29
+ o.puts "3-interrupt"
30
+ ensure
31
+ p 3
32
+ o.close
33
+ end
34
+ sleep 0.2
35
+ o.close
36
+ watcher = Gyro::Child.new(pid)
37
+ Process.kill('INT', pid)
38
+ watcher.await
39
+ buffer = i.read
40
+
41
+ puts '*' * 40
42
+ p buffer
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ Exception.__disable_sanitized_backtrace__ = true
7
+
8
+ pid = Polyphony.fork do
9
+ f = spin do
10
+ p 1
11
+ sleep 1
12
+ p 2
13
+ ensure
14
+ p 2.5
15
+ end
16
+ p 3
17
+ snooze
18
+ p 4
19
+ # f.stop
20
+ # f.join
21
+ # Fiber.current.terminate_all_children
22
+ # Fiber.current.await_all_children
23
+ p 5
24
+ end
25
+
26
+ puts "Child pid: #{pid}"
27
+ Process.wait(pid)
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ puts "parent pid: #{Process.pid}"
7
+
8
+ pid = Polyphony.fork do
9
+ puts "child pid: #{Process.pid}"
10
+
11
+ spin do
12
+ puts 'child going to sleep 1...'
13
+ sleep 1
14
+ puts 'child woke up 1'
15
+ end
16
+
17
+ suspend
18
+ end
19
+
20
+ puts "got child pid #{pid}"
21
+
22
+ puts 'parent waiting for child'
23
+ Gyro::Child.new(pid).await
24
+ puts 'parent done waiting'
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+ Exception.__disable_sanitized_backtrace__ = true
6
+
7
+ puts 'going to sleep...'
8
+ move_on_after(1) do
9
+ sleep 60
10
+ puts 'woke up'
11
+ end
12
+
13
+ puts 'going to sleep...'
14
+ move_on_after(0.5) do
15
+ t0 = Time.now
16
+ sleep(60)
17
+ ensure
18
+ puts 'woke up'
19
+ end
20
+
21
+ puts 'going to sleep...'
22
+ value = move_on_after(1, with_value: :bar) { sleep 60 }
23
+ puts "got value #{value.inspect}"
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ pong = spin_loop do
7
+ msg, ping = receive
8
+ puts msg
9
+ ping << 'pong'
10
+ end
11
+
12
+ ping = spin_loop do
13
+ pong << ['ping', Fiber.current]
14
+ msg = receive
15
+ puts msg
16
+ end
17
+
18
+ suspend
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ Thread.event_selector = ->(thread) { Gyro::Selector.new(thread) }
7
+
8
+ def bm(sym, x)
9
+ t0 = Time.now
10
+ send(sym, x)
11
+ elapsed = Time.now - t0
12
+ STDOUT.orig_puts "#{sym} #{x / elapsed}"
13
+ end
14
+
15
+ def test_queue(x)
16
+ queue = Queue.new
17
+ async = Gyro::Async.new
18
+ t1 = Thread.new do
19
+ Thread.current.setup_fiber_scheduling
20
+ counter = 0
21
+ loop {
22
+ async.await if queue.empty?
23
+ v = queue.pop
24
+ counter += 1
25
+ break if counter == x
26
+ }
27
+ ensure
28
+ Thread.current.stop_event_selector
29
+ end
30
+ t2 = Thread.new do
31
+ Thread.current.setup_fiber_scheduling
32
+ x.times { |i|
33
+ queue.push i
34
+ async.signal!
35
+ }
36
+ ensure
37
+ Thread.current.stop_event_selector
38
+ end
39
+ t1.join
40
+ t2.join
41
+ end
42
+
43
+ def test_array_mutex(x)
44
+ queue = []
45
+ mutex = Mutex.new
46
+ async = Gyro::Async.new
47
+ t1 = Thread.new {
48
+ Thread.current.setup_fiber_scheduling
49
+ counter = 0
50
+ loop {
51
+ async.await if mutex.synchronize { queue.empty? }
52
+ v = mutex.synchronize { queue.shift }
53
+ counter += 1
54
+ break if counter == x
55
+ }
56
+ }
57
+ t2 = Thread.new {
58
+ Thread.current.setup_fiber_scheduling
59
+ x.times { |i|
60
+ mutex.synchronize { queue.push i }
61
+ async.signal!
62
+ }
63
+ }
64
+ t1.join
65
+ t2.join
66
+ end
67
+
68
+ # class Gyro::Queue
69
+ # def initialize
70
+ # @wait_queue = []
71
+ # @queue = []
72
+ # end
73
+
74
+ # def <<(value)
75
+ # async = @wait_queue.pop
76
+ # if async
77
+ # async.signal! value
78
+ # else
79
+ # @queue.push value
80
+ # end
81
+ # end
82
+
83
+ # def shift
84
+ # if @queue.empty?
85
+ # async = Gyro::Async.new
86
+ # @wait_queue << async
87
+ # async.await
88
+ # else
89
+ # @queue.shift
90
+ # end
91
+ # end
92
+ # end
93
+
94
+ def test_gyro_queue(x)
95
+ queue = Gyro::Queue.new
96
+ x.times { |i| queue << i }
97
+ t1 = Thread.new do
98
+ Thread.current.setup_fiber_scheduling
99
+ x.times { queue.shift }
100
+ ensure
101
+ Thread.current.stop_event_selector
102
+ end
103
+ t2 = Thread.new do
104
+ Thread.current.setup_fiber_scheduling
105
+ x.times { |i| queue << i }
106
+ ensure
107
+ Thread.current.stop_event_selector
108
+ end
109
+ t1.join
110
+ t2.join
111
+ end
112
+
113
+ Thread.current.setup_fiber_scheduling
114
+ # bm(:test_array_mutex, 1000000)
115
+ loop {
116
+ STDOUT.orig_puts "*" * 40
117
+ bm(:test_queue, 1000000)
118
+ bm(:test_gyro_queue, 1000000)
119
+ }
120
+