polyphony 0.22 → 0.23

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