polyphony 0.22 → 0.23

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 (114) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/Gemfile.lock +9 -1
  4. data/TODO.md +13 -38
  5. data/docs/summary.md +19 -5
  6. data/docs/technical-overview/faq.md +12 -0
  7. data/examples/core/01-spinning-up-coprocesses.rb +2 -6
  8. data/examples/core/02-awaiting-coprocesses.rb +3 -1
  9. data/examples/core/03-interrupting.rb +3 -1
  10. data/examples/core/04-no-auto-run.rb +1 -3
  11. data/examples/core/cancel.rb +1 -1
  12. data/examples/core/channel_echo.rb +3 -1
  13. data/examples/core/defer.rb +3 -1
  14. data/examples/core/enumerator.rb +3 -1
  15. data/examples/core/error_bubbling.rb +35 -0
  16. data/examples/core/fork.rb +1 -1
  17. data/examples/core/genserver.rb +1 -1
  18. data/examples/core/lock.rb +3 -1
  19. data/examples/core/move_on.rb +1 -1
  20. data/examples/core/move_on_twice.rb +1 -1
  21. data/examples/core/move_on_with_ensure.rb +1 -1
  22. data/examples/core/move_on_with_value.rb +1 -1
  23. data/examples/core/multiple_spin.rb +3 -1
  24. data/examples/core/nested_cancel.rb +1 -1
  25. data/examples/core/nested_multiple_spin.rb +3 -1
  26. data/examples/core/nested_spin.rb +3 -1
  27. data/examples/core/pulse.rb +1 -1
  28. data/examples/core/resource.rb +1 -1
  29. data/examples/core/resource_cancel.rb +2 -2
  30. data/examples/core/resource_delegate.rb +1 -1
  31. data/examples/core/sleep.rb +1 -1
  32. data/examples/core/sleep_spin.rb +3 -1
  33. data/examples/core/snooze.rb +1 -1
  34. data/examples/core/spin_error.rb +2 -1
  35. data/examples/core/spin_error_backtrace.rb +1 -1
  36. data/examples/core/spin_uncaught_error.rb +3 -1
  37. data/examples/core/supervisor.rb +1 -1
  38. data/examples/core/supervisor_with_cancel_scope.rb +1 -1
  39. data/examples/core/supervisor_with_error.rb +3 -1
  40. data/examples/core/supervisor_with_manual_move_on.rb +1 -1
  41. data/examples/core/suspend.rb +1 -1
  42. data/examples/core/thread.rb +3 -3
  43. data/examples/core/thread_cancel.rb +6 -3
  44. data/examples/core/thread_pool.rb +8 -52
  45. data/examples/core/thread_pool_perf.rb +63 -0
  46. data/examples/core/throttle.rb +3 -1
  47. data/examples/core/timeout.rb +1 -1
  48. data/examples/core/wait_for_signal.rb +4 -2
  49. data/examples/fs/read.rb +1 -1
  50. data/examples/http/http2_raw.rb +1 -1
  51. data/examples/http/http_get.rb +1 -1
  52. data/examples/http/http_server.rb +2 -1
  53. data/examples/http/http_server_graceful.rb +3 -1
  54. data/examples/http/http_ws_server.rb +0 -2
  55. data/examples/http/https_wss_server.rb +0 -2
  56. data/examples/http/websocket_secure_server.rb +0 -2
  57. data/examples/http/websocket_server.rb +0 -2
  58. data/examples/interfaces/redis_channels.rb +3 -1
  59. data/examples/interfaces/redis_pubsub.rb +3 -1
  60. data/examples/interfaces/redis_pubsub_perf.rb +3 -1
  61. data/examples/io/backticks.rb +1 -1
  62. data/examples/io/cat.rb +1 -1
  63. data/examples/io/echo_client.rb +1 -1
  64. data/examples/io/echo_client_from_stdin.rb +3 -1
  65. data/examples/io/echo_pipe.rb +1 -1
  66. data/examples/io/echo_server.rb +1 -1
  67. data/examples/io/echo_server_with_timeout.rb +1 -1
  68. data/examples/io/echo_stdin.rb +1 -1
  69. data/examples/io/httparty_multi.rb +1 -1
  70. data/examples/io/io_read.rb +1 -1
  71. data/examples/io/irb.rb +1 -1
  72. data/examples/io/net-http.rb +1 -1
  73. data/examples/io/open.rb +1 -1
  74. data/examples/io/system.rb +1 -1
  75. data/examples/io/tcpserver.rb +1 -1
  76. data/examples/io/tcpsocket.rb +1 -1
  77. data/examples/performance/multi_snooze.rb +1 -1
  78. data/examples/performance/snooze.rb +18 -10
  79. data/ext/gyro/async.c +16 -9
  80. data/ext/gyro/child.c +2 -2
  81. data/ext/gyro/gyro.c +17 -10
  82. data/ext/gyro/gyro.h +2 -2
  83. data/ext/gyro/io.c +2 -2
  84. data/ext/gyro/signal.c +33 -35
  85. data/ext/gyro/timer.c +6 -73
  86. data/lib/polyphony.rb +6 -8
  87. data/lib/polyphony/core/cancel_scope.rb +32 -21
  88. data/lib/polyphony/core/coprocess.rb +26 -23
  89. data/lib/polyphony/core/global_api.rb +86 -0
  90. data/lib/polyphony/core/resource_pool.rb +1 -1
  91. data/lib/polyphony/core/supervisor.rb +47 -13
  92. data/lib/polyphony/core/thread.rb +10 -36
  93. data/lib/polyphony/core/thread_pool.rb +6 -26
  94. data/lib/polyphony/extensions/core.rb +30 -100
  95. data/lib/polyphony/extensions/io.rb +10 -7
  96. data/lib/polyphony/extensions/openssl.rb +18 -28
  97. data/lib/polyphony/http/client/agent.rb +15 -11
  98. data/lib/polyphony/http/client/http2.rb +1 -1
  99. data/lib/polyphony/version.rb +1 -1
  100. data/polyphony.gemspec +1 -0
  101. data/test/coverage.rb +45 -0
  102. data/test/helper.rb +15 -5
  103. data/test/test_async.rb +4 -4
  104. data/test/test_cancel_scope.rb +109 -0
  105. data/test/test_coprocess.rb +80 -36
  106. data/test/{test_core.rb → test_global_api.rb} +67 -13
  107. data/test/test_gyro.rb +1 -5
  108. data/test/test_io.rb +2 -2
  109. data/test/test_resource_pool.rb +19 -0
  110. data/test/test_signal.rb +10 -5
  111. data/test/test_supervisor.rb +168 -0
  112. data/test/test_timer.rb +31 -5
  113. metadata +23 -4
  114. data/lib/polyphony/auto_run.rb +0 -19
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  spin do
7
7
  puts '1 >'
@@ -14,3 +14,5 @@ spin do
14
14
  sleep(1)
15
15
  puts '2 <'
16
16
  end
17
+
18
+ suspend
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  def sleep_and_cancel
7
7
  puts "#{Time.now} going to sleep with cancel..."
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  spin do
7
7
  spin do
@@ -16,3 +16,5 @@ spin do
16
16
  puts '2 <'
17
17
  end
18
18
  end
19
+
20
+ suspend
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  spin do
7
7
  puts 'going to sleep'
@@ -15,3 +15,5 @@ spin do
15
15
  end.await
16
16
  puts "result: #{result}"
17
17
  end
18
+
19
+ suspend
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  move_on_after(3) do
7
7
  puts 'Start...'
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  resource_count = 0
7
7
  Pool = Polyphony::ResourcePool.new(limit: 3) do
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  resource_count = 0
7
7
  Pool = Polyphony::ResourcePool.new(limit: 3) do
@@ -27,4 +27,4 @@ end
27
27
  end
28
28
 
29
29
  t0 = Time.now
30
- every(10) { puts "uptime: #{Time.now - t0}" }
30
+ throttled_loop(0.1) { puts "uptime: #{Time.now - t0}" }
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  class Number
7
7
  def initialize(id)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  puts 'going to sleep...'
7
7
  sleep 1
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  spin do
7
7
  10.times do |i|
@@ -17,3 +17,5 @@ spin do
17
17
  end.await
18
18
 
19
19
  puts 'done'
20
+
21
+ suspend
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  COUNT = 10_000
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  def error(t)
7
7
  raise "hello #{t}"
@@ -14,3 +14,4 @@ end
14
14
  spin_with_error
15
15
 
16
16
  puts 'done coprocing'
17
+ suspend
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  def error(t)
7
7
  raise "hello #{t}"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  def foo
7
7
  spin do
@@ -12,3 +12,5 @@ def foo
12
12
  end
13
13
 
14
14
  foo
15
+
16
+ suspend
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  def my_sleep(t)
7
7
  puts "#{t} start"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  def my_sleep(t)
7
7
  puts "start: #{t}"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  def my_sleep(t)
7
7
  sleep(t)
@@ -20,3 +20,5 @@ spin do
20
20
  ensure
21
21
  puts "#{Time.now} woke up"
22
22
  end
23
+
24
+ suspend
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  def my_sleep(t)
7
7
  puts "start: #{t}"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  spin do
7
7
  1.times do
@@ -7,7 +7,7 @@ def lengthy_op
7
7
  IO.orig_read(__FILE__)
8
8
  end
9
9
 
10
- X = 1000
10
+ X = 10000
11
11
 
12
12
  def blocking
13
13
  t0 = Time.now
@@ -18,8 +18,8 @@ end
18
18
 
19
19
  def threaded
20
20
  t0 = Time.now
21
- data = Polyphony::Thread.spin { lengthy_op }.await
22
- X.times { Polyphony::Thread.spin { lengthy_op }.await }
21
+ data = Polyphony::Thread.spawn { lengthy_op }.await
22
+ X.times { Polyphony::Thread.spawn { lengthy_op } }
23
23
  puts "read threaded #{data.bytesize} bytes (#{Time.now - t0}s)"
24
24
  end
25
25
 
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  @op_count = 0
7
7
 
8
8
  def lengthy_op
9
9
  100.times do
10
- sleep 0.01
10
+ orig_sleep 0.01
11
11
  @op_count += 1
12
12
  end
13
13
  @op_count
@@ -15,11 +15,14 @@ end
15
15
 
16
16
  spin do
17
17
  cancel_after(0.1) do
18
- data = Polyphony::Thread.spin { lengthy_op }.await
18
+ data = Polyphony::Thread.process { lengthy_op }
19
19
  puts "slept #{data} times"
20
20
  end
21
21
  rescue Exception => e
22
22
  puts "error: #{e}"
23
23
  ensure
24
+ sleep 0.1
24
25
  puts "slept #{@op_count} times"
25
26
  end
27
+
28
+ suspend
@@ -1,61 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  def lengthy_op
7
- data = IO.read(__FILE__)
8
- data.clear
9
- # Socket.getaddrinfo('debian.org', 80)
10
- # Digest::SHA256.digest(IO.read('doc/Promise.html'))
7
+ data = IO.orig_read(__FILE__)
8
+ data.bytesize
11
9
  end
12
10
 
13
- X = 100
14
-
15
- def compare_performance
16
- t0 = Time.now
17
- X.times { lengthy_op }
18
- native_perf = X / (Time.now - t0)
19
- puts "native performance: #{native_perf}"
20
- # puts "*" * 40
21
-
22
- begin
23
- 1.times do
24
- t0 = Time.now
25
- X.times do
26
- Polyphony::ThreadPool.process { lengthy_op }
27
- end
28
- async_perf = X / (Time.now - t0)
29
- puts format(
30
- 'seq thread pool performance: %g (X %0.2f)',
31
- async_perf,
32
- async_perf / native_perf
33
- )
34
- end
35
-
36
- acc = 0
37
- count = 0
38
- 10.times do |_i|
39
- t0 = Time.now
40
- supervise do |s|
41
- X.times do
42
- s.spin { Polyphony::ThreadPool.process { lengthy_op } }
43
- end
44
- end
45
- thread_pool_perf = X / (Time.now - t0)
46
- acc += thread_pool_perf
47
- count += 1
48
- end
49
- avg_perf = acc / count
50
- puts format(
51
- 'avg thread pool performance: %g (X %0.2f)',
52
- avg_perf,
53
- avg_perf / native_perf
54
- )
55
- rescue Exception => e
56
- p e
57
- puts e.backtrace.join("\n")
58
- end
11
+ 10.times do |_i|
12
+ spin {
13
+ p [_i, 2, Polyphony::ThreadPool.process { lengthy_op }]
14
+ }
59
15
  end
60
16
 
61
- spin { compare_performance }
17
+ suspend
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ def lengthy_op
7
+ data = IO.orig_read(__FILE__)
8
+ data.clear
9
+ # Socket.getaddrinfo('debian.org', 80)
10
+ # Digest::SHA256.digest(IO.read('doc/Promise.html'))
11
+ end
12
+
13
+ X = 100
14
+
15
+ def compare_performance
16
+ t0 = Time.now
17
+ X.times { lengthy_op }
18
+ native_perf = X / (Time.now - t0)
19
+ puts "native performance: #{native_perf}"
20
+ # puts "*" * 40
21
+
22
+ begin
23
+ 1.times do
24
+ t0 = Time.now
25
+ X.times do
26
+ Polyphony::ThreadPool.process { lengthy_op }
27
+ end
28
+ async_perf = X / (Time.now - t0)
29
+ puts format(
30
+ 'seq thread pool performance: %g (X %0.2f)',
31
+ async_perf,
32
+ async_perf / native_perf
33
+ )
34
+ end
35
+
36
+ acc = 0
37
+ count = 0
38
+ 10.times do |_i|
39
+ t0 = Time.now
40
+ supervise do |s|
41
+ X.times do
42
+ s.spin { Polyphony::ThreadPool.process { lengthy_op } }
43
+ end
44
+ end
45
+ thread_pool_perf = X / (Time.now - t0)
46
+ acc += thread_pool_perf
47
+ count += 1
48
+ end
49
+ avg_perf = acc / count
50
+ puts format(
51
+ 'avg thread pool performance: %g (X %0.2f)',
52
+ avg_perf,
53
+ avg_perf / native_perf
54
+ )
55
+ rescue Exception => e
56
+ p e
57
+ puts e.backtrace.join("\n")
58
+ end
59
+ end
60
+
61
+ spin { compare_performance }
62
+
63
+ suspend
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  spin do
7
7
  throttled_loop(3) { STDOUT << '.' }
@@ -14,3 +14,5 @@ end
14
14
  spin do
15
15
  throttled_loop(interval: 1) { STDOUT << '*' }
16
16
  end
17
+
18
+ suspend
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  puts 'going to sleep...'
7
7
  Timeout.timeout(1) do
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
- require 'polyphony/auto_run'
4
+ require 'polyphony'
5
5
 
6
6
  waiter = spin do
7
7
  puts 'Waiting for HUP'
@@ -11,4 +11,6 @@ end
11
11
 
12
12
  sleep 1
13
13
  puts 'Sending HUP'
14
- Process.kill('SIGHUP', Process.pid)
14
+ Process.kill('SIGHUP', Process.pid)
15
+
16
+ suspend