polyphony 0.44.0 → 0.45.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -1
  3. data/CHANGELOG.md +41 -0
  4. data/Gemfile.lock +14 -8
  5. data/Rakefile +1 -1
  6. data/TODO.md +12 -15
  7. data/docs/_posts/2020-07-26-polyphony-0.44.md +77 -0
  8. data/docs/api-reference/thread.md +1 -1
  9. data/docs/getting-started/overview.md +14 -14
  10. data/docs/getting-started/tutorial.md +1 -1
  11. data/examples/adapters/redis_client.rb +3 -1
  12. data/examples/adapters/redis_pubsub_perf.rb +11 -8
  13. data/examples/adapters/sequel_mysql.rb +1 -1
  14. data/examples/adapters/sequel_pg.rb +24 -0
  15. data/examples/core/{02-awaiting-fibers.rb → await.rb} +0 -0
  16. data/examples/core/{xx-channels.rb → channels.rb} +0 -0
  17. data/examples/core/deferring-an-operation.rb +16 -0
  18. data/examples/core/{xx-erlang-style-genserver.rb → erlang-style-genserver.rb} +16 -9
  19. data/examples/core/{xx-forking.rb → forking.rb} +1 -1
  20. data/examples/core/handling-signals.rb +11 -0
  21. data/examples/core/{03-interrupting.rb → interrupt.rb} +0 -0
  22. data/examples/core/{xx-pingpong.rb → pingpong.rb} +7 -5
  23. data/examples/core/{xx-recurrent-timer.rb → recurrent-timer.rb} +1 -1
  24. data/examples/core/{xx-resource_delegate.rb → resource_delegate.rb} +3 -4
  25. data/examples/core/{01-spinning-up-fibers.rb → spin.rb} +1 -1
  26. data/examples/core/{xx-spin_error_backtrace.rb → spin_error_backtrace.rb} +1 -1
  27. data/examples/core/{xx-supervise-process.rb → supervise-process.rb} +8 -5
  28. data/examples/core/supervisor.rb +20 -0
  29. data/examples/core/{xx-thread-sleep.rb → thread-sleep.rb} +0 -0
  30. data/examples/core/{xx-thread_pool.rb → thread_pool.rb} +0 -0
  31. data/examples/core/{xx-throttling.rb → throttling.rb} +0 -0
  32. data/examples/core/{xx-timeout.rb → timeout.rb} +0 -0
  33. data/examples/core/{xx-using-a-mutex.rb → using-a-mutex.rb} +0 -0
  34. data/examples/core/{xx-worker-thread.rb → worker-thread.rb} +2 -2
  35. data/examples/io/{xx-backticks.rb → backticks.rb} +0 -0
  36. data/examples/io/{xx-echo_client.rb → echo_client.rb} +1 -1
  37. data/examples/io/{xx-echo_client_from_stdin.rb → echo_client_from_stdin.rb} +2 -2
  38. data/examples/io/{xx-echo_pipe.rb → echo_pipe.rb} +1 -1
  39. data/examples/io/{xx-echo_server.rb → echo_server.rb} +0 -0
  40. data/examples/io/{xx-echo_server_with_timeout.rb → echo_server_with_timeout.rb} +1 -1
  41. data/examples/io/{xx-echo_stdin.rb → echo_stdin.rb} +0 -0
  42. data/examples/io/{xx-happy-eyeballs.rb → happy-eyeballs.rb} +0 -0
  43. data/examples/io/{xx-httparty.rb → httparty.rb} +4 -13
  44. data/examples/io/{xx-irb.rb → irb.rb} +0 -0
  45. data/examples/io/{xx-net-http.rb → net-http.rb} +0 -0
  46. data/examples/io/{xx-open.rb → open.rb} +0 -0
  47. data/examples/io/pry.rb +18 -0
  48. data/examples/io/rack_server.rb +71 -0
  49. data/examples/io/raw.rb +14 -0
  50. data/examples/io/reline.rb +18 -0
  51. data/examples/io/{xx-system.rb → system.rb} +1 -1
  52. data/examples/io/{xx-tcpserver.rb → tcpserver.rb} +0 -0
  53. data/examples/io/{xx-tcpsocket.rb → tcpsocket.rb} +0 -0
  54. data/examples/io/tunnel.rb +6 -1
  55. data/examples/io/{xx-zip.rb → zip.rb} +0 -0
  56. data/examples/performance/fiber_transfer.rb +2 -1
  57. data/examples/performance/fs_read.rb +5 -6
  58. data/examples/performance/multi_snooze.rb +0 -1
  59. data/examples/{io/xx-switch.rb → performance/switch.rb} +2 -1
  60. data/examples/performance/thread-vs-fiber/{xx-httparty_multi.rb → httparty_multi.rb} +3 -4
  61. data/examples/performance/thread-vs-fiber/{xx-httparty_threaded.rb → httparty_threaded.rb} +0 -0
  62. data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +1 -1
  63. data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -1
  64. data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +1 -1
  65. data/examples/performance/thread-vs-fiber/threaded_server.rb +1 -5
  66. data/examples/performance/thread_pool_perf.rb +6 -7
  67. data/ext/polyphony/backend.h +40 -0
  68. data/ext/polyphony/event.c +3 -3
  69. data/ext/polyphony/extconf.rb +1 -1
  70. data/ext/polyphony/fiber.c +90 -13
  71. data/ext/polyphony/{libev_agent.c → libev_backend.c} +226 -224
  72. data/ext/polyphony/polyphony.c +5 -7
  73. data/ext/polyphony/polyphony.h +18 -18
  74. data/ext/polyphony/polyphony_ext.c +5 -4
  75. data/ext/polyphony/queue.c +5 -6
  76. data/ext/polyphony/ring_buffer.c +0 -1
  77. data/ext/polyphony/runqueue.c +102 -0
  78. data/ext/polyphony/runqueue_ring_buffer.c +85 -0
  79. data/ext/polyphony/runqueue_ring_buffer.h +31 -0
  80. data/ext/polyphony/thread.c +53 -102
  81. data/lib/polyphony.rb +15 -14
  82. data/lib/polyphony/adapters/fs.rb +1 -1
  83. data/lib/polyphony/adapters/irb.rb +2 -17
  84. data/lib/polyphony/adapters/mysql2.rb +1 -1
  85. data/lib/polyphony/adapters/postgres.rb +5 -5
  86. data/lib/polyphony/adapters/process.rb +2 -5
  87. data/lib/polyphony/adapters/readline.rb +17 -0
  88. data/lib/polyphony/adapters/redis.rb +1 -1
  89. data/lib/polyphony/adapters/sequel.rb +1 -1
  90. data/lib/polyphony/core/global_api.rb +19 -14
  91. data/lib/polyphony/core/resource_pool.rb +2 -2
  92. data/lib/polyphony/core/sync.rb +43 -3
  93. data/lib/polyphony/core/throttler.rb +1 -1
  94. data/lib/polyphony/extensions/core.rb +25 -32
  95. data/lib/polyphony/extensions/fiber.rb +22 -45
  96. data/lib/polyphony/extensions/io.rb +60 -16
  97. data/lib/polyphony/extensions/openssl.rb +6 -6
  98. data/lib/polyphony/extensions/socket.rb +14 -15
  99. data/lib/polyphony/extensions/thread.rb +6 -5
  100. data/lib/polyphony/version.rb +1 -1
  101. data/polyphony.gemspec +5 -3
  102. data/test/helper.rb +1 -1
  103. data/test/{test_agent.rb → test_backend.rb} +22 -22
  104. data/test/test_fiber.rb +13 -12
  105. data/test/test_global_api.rb +29 -0
  106. data/test/test_io.rb +59 -1
  107. data/test/test_kernel.rb +5 -0
  108. data/test/test_signal.rb +14 -11
  109. data/test/test_socket.rb +17 -0
  110. data/test/test_sync.rb +73 -0
  111. metadata +99 -98
  112. data/.gitbook.yaml +0 -4
  113. data/examples/adapters/concurrent-ruby.rb +0 -9
  114. data/examples/core/04-handling-signals.rb +0 -19
  115. data/examples/core/xx-agent.rb +0 -102
  116. data/examples/core/xx-at_exit.rb +0 -29
  117. data/examples/core/xx-caller.rb +0 -12
  118. data/examples/core/xx-daemon.rb +0 -14
  119. data/examples/core/xx-deadlock.rb +0 -8
  120. data/examples/core/xx-deferring-an-operation.rb +0 -14
  121. data/examples/core/xx-exception-backtrace.rb +0 -40
  122. data/examples/core/xx-fork-cleanup.rb +0 -22
  123. data/examples/core/xx-fork-spin.rb +0 -42
  124. data/examples/core/xx-fork-terminate.rb +0 -27
  125. data/examples/core/xx-move_on.rb +0 -23
  126. data/examples/core/xx-queue-async.rb +0 -120
  127. data/examples/core/xx-readpartial.rb +0 -18
  128. data/examples/core/xx-signals.rb +0 -16
  129. data/examples/core/xx-sleep-forever.rb +0 -9
  130. data/examples/core/xx-sleeping.rb +0 -25
  131. data/examples/core/xx-snooze-starve.rb +0 -16
  132. data/examples/core/xx-spin-fork.rb +0 -49
  133. data/examples/core/xx-state-machine.rb +0 -51
  134. data/examples/core/xx-stop.rb +0 -20
  135. data/examples/core/xx-supervisors.rb +0 -21
  136. data/examples/core/xx-thread-selector-sleep.rb +0 -51
  137. data/examples/core/xx-thread-selector-snooze.rb +0 -46
  138. data/examples/core/xx-thread-snooze.rb +0 -34
  139. data/examples/core/xx-timer-gc.rb +0 -17
  140. data/examples/core/xx-trace.rb +0 -79
  141. data/examples/performance/xx-array.rb +0 -11
  142. data/examples/performance/xx-fiber-switch.rb +0 -9
  143. data/examples/performance/xx-snooze.rb +0 -15
  144. data/examples/xx-spin.rb +0 -32
  145. data/ext/polyphony/agent.h +0 -41
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 04c1c1221d46b1b9169aa04c5896c8d68c20fa11d64554e76b7452710423f142
4
- data.tar.gz: 519528e0a3dfd323620869d4a7e43e4769cf3c1b5f0ea405cf341efc6fd534f6
3
+ metadata.gz: fe5d86b07fc6f29d01897a7790deac8f0544bb61dbd486fb8ea104dd315b0e80
4
+ data.tar.gz: 3e1086b9395d63835a09051c52b7f8496013f190149df35532333b6c27b74169
5
5
  SHA512:
6
- metadata.gz: de8ac460dd05b051057ffab1c155c6b2d675cc623b98549333ba1defbc99f4efb738ff4a34a9f8c14bd3cb9ab0cab5356aa34a2308daa73273a6ef8719565bc4
7
- data.tar.gz: c26b254559e484774574555dc895cf072bda8061b92fed26d8e61e7172523fe0faf2750cd2f924db3a25b59583b673ebe5f14749fd6f1279ca2e7e7b7745490b
6
+ metadata.gz: d6c7a78a46b9084f60ee838e82b7cde6f287eea2c500f779e5014103a400da98dc066adef58631033591a8de5278cc4f7b95ba8dcdac3ad22ecd68668a7d68e4
7
+ data.tar.gz: d32e7def9aa63ecb5c53b46020079e3384809ff786478e0b87fce1b141abb85d3c69d1f490b1d0a3bcbfaf972a3779939ac42bec512b12132d3b46b159754de5
@@ -81,6 +81,7 @@ Lint/SuppressedException:
81
81
  - examples/**/*.rb
82
82
 
83
83
  Metrics/MethodLength:
84
+ Max: 12
84
85
  Exclude:
85
86
  - lib/polyphony/http/server/rack.rb
86
87
  - lib/polyphony/extensions/io.rb
@@ -95,6 +96,7 @@ Metrics/ModuleLength:
95
96
  Metrics/ClassLength:
96
97
  Exclude:
97
98
  - lib/polyphony/http/server/http1.rb
99
+ - lib/polyphony/extensions/io.rb
98
100
  - test/**/*.rb
99
101
  - examples/**/*.rb
100
102
 
@@ -111,6 +113,7 @@ Style/Documentation:
111
113
  Exclude:
112
114
  - test/**/*.rb
113
115
  - examples/**/*.rb
116
+ - lib/polyphony/adapters/**/*.rb
114
117
 
115
118
  Style/FormatString:
116
119
  Exclude:
@@ -172,4 +175,8 @@ Style/RedundantRegexpEscape:
172
175
  Enabled: true
173
176
 
174
177
  Style/SlicingWithRange:
175
- Enabled: true
178
+ Enabled: true
179
+
180
+ Style/RaiseArgs:
181
+ Exclude:
182
+ - lib/polyphony/extensions/fiber.rb
@@ -1,3 +1,44 @@
1
+ ## 0.45.5
2
+
3
+ * Fix compilation error (#43)
4
+ * Add support for resetting move_on_after, cancel_after timeouts
5
+ * Optimize anti-event starvation polling
6
+ * Implement optimized runqueue for better performance
7
+ * Schedule parent with priority on uncaught exception
8
+ * Fix race condition in `Mutex#synchronize` (#41)
9
+
10
+ ## 0.45.4
11
+
12
+ * Improve signal trapping mechanism
13
+
14
+ ## 0.45.3
15
+
16
+ * Don't swallow error in `Process#kill_and_await`
17
+ * Add `Fiber#mailbox` attribute reader
18
+ * Fix bug in `Fiber.await`
19
+ * Implement `IO#getc`, `IO#getbyte`
20
+
21
+ ## 0.45.2
22
+
23
+ * Rewrite `Fiber#<<`, `Fiber#await`, `Fiber#receive` in C
24
+
25
+ ## 0.45.1
26
+
27
+ * Fix Net::HTTP compatibility
28
+ * Fix fs adapter
29
+ * Improve performance of IO#puts
30
+ * Mutex#synchronize
31
+ * Fix Socket#connect
32
+ * Cleanup code
33
+ * Improve support for Ruby 3 keyword args
34
+
35
+ ## 0.45.0
36
+
37
+ * Cleanup code
38
+ * Rename `Agent` to `Backend`
39
+ * Implement `Polyphony::ConditionVariable`
40
+ * Fix Kernel.system
41
+
1
42
  ## 0.44.0 2020-07-25
2
43
 
3
44
  * Fix reentrant `ResourcePool` (#38)
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.44.0)
4
+ polyphony (0.45.5)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -11,6 +11,7 @@ GEM
11
11
  ansi (1.5.0)
12
12
  ast (2.4.0)
13
13
  builder (3.2.4)
14
+ coderay (1.1.3)
14
15
  colorator (1.1.0)
15
16
  concurrent-ruby (1.1.6)
16
17
  docile (1.3.2)
@@ -22,7 +23,7 @@ GEM
22
23
  forwardable-extended (2.6.0)
23
24
  hiredis (0.6.3)
24
25
  http_parser.rb (0.6.0)
25
- httparty (0.17.0)
26
+ httparty (0.17.1)
26
27
  mime-types (~> 3.0)
27
28
  multi_xml (>= 0.5.2)
28
29
  i18n (0.9.5)
@@ -60,11 +61,11 @@ GEM
60
61
  listen (3.2.1)
61
62
  rb-fsevent (~> 0.10, >= 0.10.3)
62
63
  rb-inotify (~> 0.9, >= 0.9.10)
63
- localhost (1.1.4)
64
64
  mercenary (0.3.6)
65
+ method_source (1.0.0)
65
66
  mime-types (3.3.1)
66
67
  mime-types-data (~> 3.2015)
67
- mime-types-data (3.2019.1009)
68
+ mime-types-data (3.2020.0512)
68
69
  minitest (5.13.0)
69
70
  minitest-reporters (1.4.2)
70
71
  ansi
@@ -79,10 +80,14 @@ GEM
79
80
  pathutil (0.16.2)
80
81
  forwardable-extended (~> 2.6)
81
82
  pg (1.1.4)
83
+ pry (0.13.1)
84
+ coderay (~> 1.1)
85
+ method_source (~> 1.0)
82
86
  public_suffix (4.0.3)
87
+ rack (2.2.3)
83
88
  rainbow (3.0.0)
84
89
  rake (12.3.3)
85
- rake-compiler (1.0.5)
90
+ rake-compiler (1.1.1)
86
91
  rake
87
92
  rb-fsevent (0.10.3)
88
93
  rb-inotify (0.10.1)
@@ -124,18 +129,19 @@ PLATFORMS
124
129
  DEPENDENCIES
125
130
  hiredis (= 0.6.3)
126
131
  http_parser.rb (~> 0.6.0)
127
- httparty (= 0.17.0)
132
+ httparty (= 0.17.1)
128
133
  jekyll (~> 3.8.6)
129
134
  jekyll-remote-theme (~> 0.4.1)
130
135
  jekyll-seo-tag (~> 2.6.1)
131
136
  just-the-docs (~> 0.3.0)
132
- localhost (= 1.1.4)
133
137
  minitest (= 5.13.0)
134
138
  minitest-reporters (= 1.4.2)
135
139
  mysql2 (= 0.5.3)
136
140
  pg (= 1.1.4)
137
141
  polyphony!
138
- rake-compiler (= 1.0.5)
142
+ pry (= 0.13.1)
143
+ rack (>= 2.0.8, < 2.3.0)
144
+ rake-compiler (= 1.1.1)
139
145
  redis (= 4.1.0)
140
146
  rubocop (= 0.85.1)
141
147
  sequel (= 5.34.0)
data/Rakefile CHANGED
@@ -20,7 +20,7 @@ task :stress_test do
20
20
  end
21
21
 
22
22
  task :docs do
23
- exec 'RUBYOPT=-W0 jekyll serve -s docs -H ec2-35-158-110-38.eu-central-1.compute.amazonaws.com'
23
+ exec 'RUBYOPT=-W0 jekyll serve -s docs -H ec2-18-156-117-172.eu-central-1.compute.amazonaws.com'
24
24
  end
25
25
 
26
26
  CLEAN.include "**/*.o", "**/*.so", "**/*.bundle", "**/*.jar", "pkg", "tmp"
data/TODO.md CHANGED
@@ -1,10 +1,15 @@
1
- - Adapter for Pry, or maybe just an adapter for readline
2
- - Rename Agent to Backend
3
- - Review all code
4
- - Cleanup C code
5
- - Cleanup Ruby code (use Rubocop)
6
- - Cleanup and annotate examples (and remove all the examples used for
7
- debugging). Focus on examples that serve as "how-to".
1
+ - io_uring
2
+
3
+ 0.46
4
+
5
+ - Adapter for io/console (what does `IO#raw` do?)
6
+ - Adapter for Pry and IRB (Which fixes #5 and #6)
7
+ - Improve `#supervise`. It does not work as advertised, and seems to exhibit an
8
+ inconsistent behaviour (see supervisor example).
9
+ - Fix backtrace for `Timeout.timeout` API (see timeout example).
10
+ - Check why worker-thread example doesn't work.
11
+
12
+ 0.47
8
13
 
9
14
  - Debugging
10
15
  - Eat your own dogfood: need a good tool to check what's going on when some
@@ -118,8 +123,6 @@
118
123
  - discuss using `snooze` for ensuring responsiveness when executing CPU-bound work
119
124
 
120
125
 
121
- ## 0.45
122
-
123
126
  ### Some more API work, more docs
124
127
 
125
128
  - sintra app with database access (postgresql)
@@ -131,14 +134,10 @@
131
134
  - proceed from there
132
135
 
133
136
 
134
- ## 0.46
135
-
136
137
  ### Sinatra / Sidekiq
137
138
 
138
139
  - Pull out redis/postgres code, put into new `polyphony-xxx` gems
139
140
 
140
- ## 0.47
141
-
142
141
  ### Testing && Docs
143
142
 
144
143
  - More tests
@@ -149,8 +148,6 @@
149
148
  - `IO.foreach`
150
149
  - `Process.waitpid`
151
150
 
152
- ## 0.48 DNS
153
-
154
151
  ### DNS client
155
152
 
156
153
  ```ruby
@@ -0,0 +1,77 @@
1
+ # Polyphony 0.44.1
2
+
3
+ ## More performance, more compatibility, more robustness
4
+
5
+ The last three weeks have been very busy for Polyphony. Since I first presented
6
+ Polyphony here and elsewhere, 17 issues were closed, 10 pull requests were
7
+ merged, and 144 commits were made by 4 different authors. I'm really
8
+ excited about Polyphony and the momentum it seems to be gathering. Your
9
+ reactions have been very positive so far (it even got [tweeted by
10
+ Matz!](https://twitter.com/yukihiro_matz/status/1279289318083715073))
11
+
12
+ I'm even more excited about the contributions Polyphony is starting to get from
13
+ other developers. Thank you [Will](https://github.com/wjordan),
14
+ [Máximo](https://github.com/ElMassimo) and [Trent](https://github.com/misfo) for
15
+ your valuable contributions! Also, the Polyphony project has now got a logo
16
+ designed by my friend [Gérald Morales](https://webocube.com/).
17
+
18
+ I'd like to encourage other developers to get in on the action and start
19
+ contributing by testing Polyphony, creating issues and writing code and
20
+ documentation. Together we can make Polyphony a game-changer for developing
21
+ concurrent apps in Ruby, and finally put to rest the notion that "Ruby is slow"!
22
+
23
+ Since the last public release of Polyphony, we have focused on fixing bugs,
24
+ improving performance and introducing new features that improve the Polyphony
25
+ developer experience. Polyphony 0.44 is up to 20% percent faster than the
26
+ previous release, due notably to a new ring-buffer implementation used by the
27
+ fiber run queue and the `Polyphony::Queue` class, a new `Backend#read_loop` API
28
+ for tighter server loops, and minimizing `fcntl` syscalls when doing I/O. These
29
+ and other minor improvements have resulted in Polyphony first crossing the
30
+ 50,000 requests per second threshold for the first time in a minimal [rack
31
+ server
32
+ example](https://github.com/digital-fabric/polyphony/blob/master/examples/io/xx-rack_server.rb).
33
+
34
+ Notable new features include a MySQL adapter, a Sequel adapter, and a new
35
+ `Fiber#interject` API that allows executing arbitrary code on arbitrary fibers.
36
+
37
+ We have also fixed numerous bugs, among which an issue building Polyphony on
38
+ MacOS, problems issuing `Net::HTTP` requests with secure URLs, an issue with
39
+ `YAML.load` and much more...
40
+
41
+ For the full list of changes please consult the [change log](https://github.com/digital-fabric/polyphony/blob/master/CHANGELOG.md).
42
+
43
+ ## What's next for Polyphony?
44
+
45
+ The next release of Polyphony will focus on full support IRB and Pry. Being able
46
+ to run operations in the background in IRB and Pry can be very beneficial, most
47
+ of all when developing and when debugging running processes using `binding.pry`
48
+ for example.
49
+
50
+ Subsequent releases will introduce a whole new full-featured debugger for
51
+ fiber-aware concurrent apps, and eventually full support for Sequel, Sinatra,
52
+ Hanami, Sidekiq and other major areas of the Ruby ecosystem.
53
+
54
+ ## Tipi - a polyphonic web server for Ruby
55
+
56
+ [Tipi](https://github.com/digital-fabric/tipi) is a new web server for Ruby
57
+ apps. It is intended to be *the* go-to app server for Ruby apps looking for
58
+ robustness, scalability and performance. Tipi already supports HTTP/1, HTTP/2,
59
+ WebSockets and SSL termination. It can currently drive simple Rack apps. In the
60
+ future Tipi will be fully compliant with the Rack specification, and will also
61
+ offer a static file server, a rich configuration and automatic TLS certificates
62
+ (using Let's Encrypt) out of the box.
63
+
64
+ For those wondering about performance, here are some preliminary numbers (see
65
+ disclaimer below):
66
+
67
+ - HTTP, hello world, single process: ~50000 requests/second
68
+ - HTTP, Rack hello world app, single process: ~33000 requests/second
69
+ - HTTP, Rack hello world, 4 worker processes: ~95000 requests/second
70
+ - HTTPS, hello world, single process: ~20000 requests/second
71
+ - HTTPS, hello world, 4 worker processes: ~72000 requests/second
72
+
73
+ Disclaimer: these numbers should be taken with a grain of salt. They do not
74
+ follow any established benchmarking methodology, and may vary significantly. The
75
+ different configurtations were benchmarked using the command: `wrk -d10 -t1 -c10
76
+ "<http|https>://127.0.0.1:1234/"` on the same machine (an `m2.xlarge` instance)
77
+ as the server. In the future Tipi's performance might substantially change. YMMV.
@@ -12,7 +12,7 @@ Polyphony enhances the core `Thread` class with APIs for switching and
12
12
  scheduling fibers, and reimplements some of its APIs such as `Thread#raise`
13
13
  using fibers which, incidentally, make it safe.
14
14
 
15
- Each thread has its own run queue and its own system agent. While running
15
+ Each thread has its own run queue and its own system backend. While running
16
16
  multiple threads does not result in true parallelism in MRI Ruby, sometimes
17
17
  multithreading is inevitable, for instance when using third-party gems that
18
18
  spawn threads, or when calling blocking APIs that are not fiber-aware.
@@ -341,25 +341,25 @@ move_on_after(10) { perform_query }
341
341
  cancel_after(10) { perform_query }
342
342
  ```
343
343
 
344
- ## The System Agent
344
+ ## The Polyphony Backend
345
345
 
346
346
  In order to implement automatic fiber switching when performing blocking
347
- operations, Polyphony introduces a concept called the *system agent*. The system
348
- agent is an object having a uniform interface, that performs all blocking
347
+ operations, Polyphony introduces a concept called the *system backend*. The system
348
+ backend is an object having a uniform interface, that performs all blocking
349
349
  operations.
350
350
 
351
351
  While a standard event loop-based solution would implement a blocking call
352
- separately from the fiber scheduling, the system agent integrates the two to
352
+ separately from the fiber scheduling, the system backend integrates the two to
353
353
  create a blocking call that is already knows how to switch and schedule fibers.
354
354
  For example, in Polyphony all APIs having to do with reading from files or
355
- sockets end up calling `Thread.current.agent.read`, which does all the work.
355
+ sockets end up calling `Thread.current.backend.read`, which does all the work.
356
356
 
357
357
  This design offers some major advantages over other designs. It minimizes memory
358
358
  allocations, of both Ruby objects and C structures. For example, instead of
359
359
  having to allocate libev watchers on the heap and then pass them around, they
360
360
  are allocated on the stack instead, which saves up on both memory and CPU cycles.
361
361
 
362
- In addition, the agent interface includes two methods that allow maximizing
362
+ In addition, the backend interface includes two methods that allow maximizing
363
363
  server performance by accepting connections and reading from sockets in a tight
364
364
  loop. Here's a naive implementation of an HTTP/1 server:
365
365
 
@@ -372,7 +372,7 @@ def handle_client(socket)
372
372
  reqs = []
373
373
  parser.on_message_complete = proc { |env| reqs << { foo: :bar } }
374
374
 
375
- Thread.current.agent.read_loop(socket) do |data|
375
+ Thread.current.backend.read_loop(socket) do |data|
376
376
  parser << data
377
377
  reqs.each { |r| reply(socket, r) }
378
378
  reqs.clear
@@ -388,20 +388,20 @@ end
388
388
  server = TCPServer.open('0.0.0.0', 1234)
389
389
  puts "listening on port 1234"
390
390
 
391
- Thread.current.agent.accept_loop(server) do |client|
391
+ Thread.current.backend.accept_loop(server) do |client|
392
392
  spin { handle_client(client) }
393
393
  end
394
394
  ```
395
395
 
396
- The `#read_loop` and `#accept_loop` agent methods implement tight loops that
396
+ The `#read_loop` and `#accept_loop` backend methods implement tight loops that
397
397
  provide a significant boost to performance (up to +30% better throughput.)
398
398
 
399
- Currently, Polyphony includes a single system agent based on
399
+ Currently, Polyphony includes a single system backend based on
400
400
  [libev](http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod). In the future,
401
- Polyphony will include other platform-specific system agents, such as a Windows
402
- agent using
401
+ Polyphony will include other platform-specific system backends, such as a Windows
402
+ backend using
403
403
  [IOCP](https://docs.microsoft.com/en-us/windows/win32/fileio/i-o-completion-ports),
404
- or an [io_uring](https://unixism.net/loti/what_is_io_uring.html) agent,
404
+ or an [io_uring](https://unixism.net/loti/what_is_io_uring.html) backend,
405
405
  which might be a game-changer for writing highly-concurrent Ruby-based web apps.
406
406
 
407
407
  ## Writing Web Apps with Polyphony
@@ -482,5 +482,5 @@ reach version 1.0. Here are some of the exciting directions we're working on.
482
482
 
483
483
  - Support for more core and stdlib APIs
484
484
  - More adapters for gems with C-extensions, such as `mysql`, `sqlite3` etc
485
- - Use `io_uring` agent as alternative to the libev agent
485
+ - Use `io_uring` backend as alternative to the libev backend
486
486
  - More concurrency constructs for building highly concurrent applications
@@ -123,7 +123,7 @@ suspend # The main fiber suspends, waiting for all other work to finish
123
123
  sleep 1 # The sleeper fiber goes to sleep
124
124
  Gyro::Timer.new(1, 0).await # A timer event watcher is setup and yields
125
125
  Thread.current.switch_fiber # Polyphony looks for other runnable fibers
126
- Thread.current.agent.poll # With no work left, the event loop is ran
126
+ Thread.current.backend.poll # With no work left, the event loop is ran
127
127
  fiber.schedule # The timer event fires, scheduling the sleeper fiber
128
128
  # <= The sleep method returns
129
129
  puts "Woke up"
@@ -3,7 +3,9 @@
3
3
  require 'bundler/setup'
4
4
  require 'polyphony/adapters/redis'
5
5
 
6
- redis = Redis.new
6
+ ::Exception.__disable_sanitized_backtrace__ = true
7
+
8
+ redis = Redis.new(host: ENV['REDIS_HOST'] || 'localhost')
7
9
 
8
10
  X = 10
9
11
 
@@ -6,7 +6,7 @@ require 'json'
6
6
 
7
7
  X_SESSIONS = 1000
8
8
  X_NODES = 10_000
9
- X_SUBSCRIPTIONS_PER_SESSION = 100
9
+ X_SUBSCRIPTIONS_PER_SESSION = 1000
10
10
 
11
11
  $sessions = []
12
12
  X_SESSIONS.times do
@@ -17,8 +17,11 @@ X_SESSIONS.times do
17
17
  }
18
18
  end
19
19
 
20
+ REDIS_HOST = ENV['REDIS_HOST'] || 'localhost'
21
+ p redis_host: REDIS_HOST
22
+
20
23
  spin do
21
- redis = Redis.new
24
+ redis = Redis.new(host: REDIS_HOST)
22
25
  redis.subscribe('events') do |on|
23
26
  on.message do |_, message|
24
27
  distribute_event(JSON.parse(message, symbolize_names: true))
@@ -30,18 +33,18 @@ $update_count = 0
30
33
 
31
34
  def distribute_event(event)
32
35
  $update_count += 1
33
- # t0 = Time.now
36
+ t0 = Time.now
34
37
  count = 0
35
38
  $sessions.each do |s|
36
39
  count += 1 if s[:subscriptions].include?(event[:path])
37
40
  end
38
- # elapsed = Time.now - t0
39
- # rate = X_SESSIONS / elapsed
40
- # puts "elapsed: #{elapsed} (#{rate}/s)" if $update_count % 100 == 0
41
+ elapsed = Time.now - t0
42
+ rate = X_SESSIONS / elapsed
43
+ puts "elapsed: #{elapsed} (#{rate}/s)" if $update_count % 100 == 0
41
44
  end
42
45
 
43
46
  spin do
44
- redis = Redis.new
47
+ redis = Redis.new(host: REDIS_HOST)
45
48
  throttled_loop(1000) do
46
49
  redis.publish('events', { path: "node#{rand(X_NODES)}" }.to_json)
47
50
  end
@@ -60,7 +63,7 @@ spin do
60
63
  end
61
64
  end
62
65
 
63
- trap(:int) do
66
+ trap('SIGINT') do
64
67
  puts 'bye...'
65
68
  exit!
66
69
  end