polyphony 0.17 → 0.19
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 +4 -4
- data/CHANGELOG.md +15 -0
- data/Gemfile.lock +11 -3
- data/README.md +18 -18
- data/TODO.md +5 -21
- data/examples/core/channel_echo.rb +3 -3
- data/examples/core/enumerator.rb +1 -1
- data/examples/core/fork.rb +1 -1
- data/examples/core/genserver.rb +1 -1
- data/examples/core/lock.rb +3 -3
- data/examples/core/multiple_spawn.rb +2 -2
- data/examples/core/nested_async.rb +1 -1
- data/examples/core/nested_multiple_spawn.rb +3 -3
- data/examples/core/resource_cancel.rb +1 -1
- data/examples/core/sleep_spawn.rb +2 -2
- data/examples/core/spawn.rb +1 -1
- data/examples/core/spawn_cancel.rb +1 -1
- data/examples/core/spawn_error.rb +4 -4
- data/examples/core/supervisor.rb +1 -1
- data/examples/core/supervisor_with_error.rb +1 -1
- data/examples/core/supervisor_with_manual_move_on.rb +1 -1
- data/examples/core/thread.rb +2 -2
- data/examples/core/thread_cancel.rb +2 -2
- data/examples/core/thread_pool.rb +1 -1
- data/examples/core/throttle.rb +3 -3
- data/examples/core/timeout.rb +10 -0
- data/examples/fs/read.rb +1 -1
- data/examples/http/http_client.rb +1 -1
- data/examples/http/http_get.rb +7 -0
- data/examples/http/http_parse_experiment.rb +118 -0
- data/examples/http/http_proxy.rb +81 -0
- data/examples/http/http_server.rb +15 -4
- data/examples/http/http_server_forked.rb +2 -2
- data/examples/http/http_server_throttled.rb +1 -1
- data/examples/http/http_ws_server.rb +2 -2
- data/examples/http/https_server.rb +5 -1
- data/examples/http/https_wss_server.rb +1 -1
- data/examples/http/rack_server_https_forked.rb +1 -1
- data/examples/interfaces/pg_client.rb +1 -1
- data/examples/interfaces/pg_pool.rb +1 -1
- data/examples/interfaces/redis_channels.rb +5 -5
- data/examples/interfaces/redis_pubsub.rb +2 -2
- data/examples/interfaces/redis_pubsub_perf.rb +3 -3
- data/examples/io/echo_client.rb +2 -2
- data/examples/io/echo_pipe.rb +17 -0
- data/examples/io/echo_server.rb +1 -1
- data/examples/io/echo_server_with_timeout.rb +1 -1
- data/examples/io/httparty.rb +10 -0
- data/examples/io/httparty_multi.rb +29 -0
- data/examples/io/httparty_threaded.rb +25 -0
- data/examples/io/irb.rb +15 -0
- data/examples/io/net-http.rb +15 -0
- data/examples/io/system.rb +1 -1
- data/examples/io/tcpsocket.rb +18 -0
- data/examples/performance/perf_multi_snooze.rb +2 -2
- data/examples/performance/perf_snooze.rb +17 -20
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -1
- data/ext/ev/ev.h +9 -1
- data/ext/ev/ev_ext.c +4 -1
- data/ext/ev/ev_module.c +36 -22
- data/ext/ev/extconf.rb +1 -1
- data/ext/ev/io.c +23 -23
- data/ext/ev/signal.c +1 -1
- data/ext/ev/socket.c +161 -0
- data/lib/polyphony/core/coprocess.rb +1 -1
- data/lib/polyphony/core/fiber_pool.rb +2 -2
- data/lib/polyphony/core/supervisor.rb +2 -18
- data/lib/polyphony/extensions/io.rb +19 -6
- data/lib/polyphony/extensions/kernel.rb +17 -5
- data/lib/polyphony/extensions/socket.rb +40 -1
- data/lib/polyphony/http/agent.rb +56 -25
- data/lib/polyphony/http/http1_adapter.rb +254 -0
- data/lib/polyphony/http/http2_adapter.rb +157 -0
- data/lib/polyphony/http/{http2_request.rb → request.rb} +25 -22
- data/lib/polyphony/http/server.rb +19 -11
- data/lib/polyphony/net.rb +10 -6
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +6 -5
- data/test/test_coprocess.rb +9 -9
- data/test/test_core.rb +14 -14
- data/test/test_io.rb +4 -4
- data/test/test_kernel.rb +1 -1
- metadata +48 -23
- data/lib/polyphony/http/http1.rb +0 -124
- data/lib/polyphony/http/http1_request.rb +0 -83
- data/lib/polyphony/http/http2.rb +0 -65
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'bundler/setup'
|
4
4
|
require 'polyphony/redis'
|
5
5
|
|
6
|
-
|
6
|
+
spin do
|
7
7
|
redis = Redis.new
|
8
8
|
redis.subscribe('redis-channel') do |on|
|
9
9
|
on.message do |channel, message|
|
@@ -13,7 +13,7 @@ coproc do
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
spin do
|
17
17
|
redis = Redis.new
|
18
18
|
move_on_after(3) do
|
19
19
|
throttled_loop(1) do
|
@@ -17,7 +17,7 @@ X_SESSIONS.times do
|
|
17
17
|
}
|
18
18
|
end
|
19
19
|
|
20
|
-
|
20
|
+
spin do
|
21
21
|
redis = Redis.new
|
22
22
|
redis.subscribe('events') do |on|
|
23
23
|
on.message do |_, message|
|
@@ -40,14 +40,14 @@ def distribute_event(event)
|
|
40
40
|
# puts "elapsed: #{elapsed} (#{rate}/s)" if $update_count % 100 == 0
|
41
41
|
end
|
42
42
|
|
43
|
-
|
43
|
+
spin do
|
44
44
|
redis = Redis.new
|
45
45
|
throttled_loop(1000) do
|
46
46
|
redis.publish('events', {path: "node#{rand(X_NODES)}"}.to_json)
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
|
50
|
+
spin do
|
51
51
|
last_count = 0
|
52
52
|
last_stamp = Time.now
|
53
53
|
throttled_loop(1) do
|
data/examples/io/echo_client.rb
CHANGED
@@ -5,11 +5,11 @@ require 'polyphony'
|
|
5
5
|
|
6
6
|
socket = Polyphony::Net.tcp_connect('127.0.0.1', 1234)
|
7
7
|
|
8
|
-
writer =
|
8
|
+
writer = spin do
|
9
9
|
throttled_loop(1) { socket << "#{Time.now}\n" rescue nil }
|
10
10
|
end
|
11
11
|
|
12
|
-
reader =
|
12
|
+
reader = spin do
|
13
13
|
puts "received from echo server:"
|
14
14
|
while data = socket.readpartial(8192)
|
15
15
|
STDOUT << data
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
i, o = IO.pipe
|
7
|
+
|
8
|
+
puts "Write something:"
|
9
|
+
spin {
|
10
|
+
throttled_loop(1, count: 3) { o << STDIN.gets }
|
11
|
+
o.close
|
12
|
+
}
|
13
|
+
|
14
|
+
while data = i.readpartial(8192)
|
15
|
+
STDOUT << "You wrote: #{data}"
|
16
|
+
end
|
17
|
+
|
data/examples/io/echo_server.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
require 'httparty'
|
6
|
+
|
7
|
+
url = 'http://127.0.0.1:4411/?q=time'
|
8
|
+
results = []
|
9
|
+
|
10
|
+
t0 = Time.now
|
11
|
+
move_on_after(3) do
|
12
|
+
supervise do |s|
|
13
|
+
10.times do
|
14
|
+
s.spin do
|
15
|
+
loop do
|
16
|
+
STDOUT << '!'
|
17
|
+
if (result = HTTParty.get(url))
|
18
|
+
results << result
|
19
|
+
STDOUT << '.'
|
20
|
+
end
|
21
|
+
rescue => e
|
22
|
+
p e
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
puts "done"
|
28
|
+
end
|
29
|
+
puts "got #{results.size} (#{results.size / (Time.now - t0)}/s)"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'httparty'
|
4
|
+
|
5
|
+
url = 'http://127.0.0.1:4411/?q=time'
|
6
|
+
results = Queue.new
|
7
|
+
|
8
|
+
t0 = Time.now
|
9
|
+
threads = []
|
10
|
+
10.times do
|
11
|
+
threads << Thread.new do
|
12
|
+
loop do
|
13
|
+
STDOUT << '!'
|
14
|
+
if (result = HTTParty.get(url))
|
15
|
+
results << result
|
16
|
+
STDOUT << '.'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
sleep 3
|
23
|
+
threads.each(&:kill)
|
24
|
+
puts "done"
|
25
|
+
puts "got #{results.size} (#{results.size / (Time.now - t0)}/s)"
|
data/examples/io/irb.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
require 'net/http'
|
6
|
+
|
7
|
+
uri = URI('http://realiteq.net/?q=time')
|
8
|
+
|
9
|
+
begin
|
10
|
+
puts Net::HTTP.get(uri)
|
11
|
+
rescue => e
|
12
|
+
p e
|
13
|
+
puts "*" * 40
|
14
|
+
puts e.backtrace[0..4].join("\n")
|
15
|
+
end
|
data/examples/io/system.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
socket = TCPSocket.new('realiteq.net', 80)
|
7
|
+
|
8
|
+
timer = spin { throttled_loop(20) { STDOUT << '.' } }
|
9
|
+
|
10
|
+
5.times do
|
11
|
+
socket.send("GET /?q=time HTTP/1.1\r\nHost: realiteq.net\r\n\r\n", 0)
|
12
|
+
socket.recv(8192)
|
13
|
+
STDOUT << "*"
|
14
|
+
end
|
15
|
+
|
16
|
+
timer.stop
|
17
|
+
socket.close
|
18
|
+
puts
|
@@ -5,26 +5,23 @@ require 'polyphony'
|
|
5
5
|
|
6
6
|
X = 1_000_000
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
STDOUT << "Fiber.yield: "
|
9
|
+
f = Fiber.new do
|
10
|
+
loop { Fiber.yield }
|
11
|
+
end
|
12
|
+
t0 = Time.now
|
13
|
+
X.times { f.resume }
|
14
|
+
dt = Time.now - t0
|
15
|
+
puts "%d/s" % (X / dt)
|
16
|
+
|
17
|
+
# STDOUT << "Kernel#sleep: "
|
11
18
|
# t0 = Time.now
|
12
|
-
# X.times {
|
19
|
+
# X.times { sleep(0) }
|
13
20
|
# dt = Time.now - t0
|
14
|
-
# puts "
|
21
|
+
# puts "%d/s" % (X / dt)
|
15
22
|
|
16
|
-
#
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
# puts "#{X / dt.to_f}/s"
|
22
|
-
# end
|
23
|
-
|
24
|
-
# snooze
|
25
|
-
coproc do
|
26
|
-
t0 = Time.now
|
27
|
-
X.times { snooze }
|
28
|
-
dt = Time.now - t0
|
29
|
-
puts "#{X / dt.to_f}/s"
|
30
|
-
end
|
23
|
+
STDOUT << "Kernel#snooze: "
|
24
|
+
t0 = Time.now
|
25
|
+
X.times { snooze }
|
26
|
+
dt = Time.now - t0
|
27
|
+
puts "%d/s" % (X / dt)
|
data/ext/ev/ev.h
CHANGED
@@ -9,6 +9,14 @@ void EV_add_watcher_ref(VALUE obj);
|
|
9
9
|
void EV_del_watcher_ref(VALUE obj);
|
10
10
|
void EV_async_free(void *p);
|
11
11
|
|
12
|
+
VALUE IO_read_watcher(VALUE io);
|
13
|
+
VALUE IO_write_watcher(VALUE io);
|
14
|
+
VALUE EV_IO_await(VALUE self);
|
15
|
+
|
16
|
+
int io_setstrbuf(VALUE *str, long len);
|
17
|
+
void io_set_read_length(VALUE str, long n, int shrinkable);
|
18
|
+
VALUE io_enc_str(VALUE str, rb_io_t *fptr);
|
19
|
+
|
12
20
|
#define SCHEDULE_FIBER(obj, args...) rb_funcall(obj, ID_transfer, args)
|
13
21
|
#define YIELD_TO_REACTOR() rb_funcall(EV_reactor_fiber, ID_transfer, 0)
|
14
22
|
|
@@ -29,4 +37,4 @@ extern ID ID_R;
|
|
29
37
|
extern ID ID_W;
|
30
38
|
extern ID ID_RW;
|
31
39
|
|
32
|
-
#endif /* RUBY_EV_H */
|
40
|
+
#endif /* RUBY_EV_H */
|
data/ext/ev/ev_ext.c
CHANGED
@@ -7,6 +7,7 @@ void Init_EV_Child();
|
|
7
7
|
void Init_EV_IO();
|
8
8
|
void Init_EV_Signal();
|
9
9
|
void Init_EV_Timer();
|
10
|
+
void Init_Socket();
|
10
11
|
|
11
12
|
void Init_ev_ext() {
|
12
13
|
ev_set_allocator(xrealloc);
|
@@ -17,4 +18,6 @@ void Init_ev_ext() {
|
|
17
18
|
Init_EV_IO();
|
18
19
|
Init_EV_Signal();
|
19
20
|
Init_EV_Timer();
|
20
|
-
|
21
|
+
|
22
|
+
Init_Socket();
|
23
|
+
}
|
data/ext/ev/ev_module.c
CHANGED
@@ -17,12 +17,14 @@ static VALUE EV_post_fork(VALUE self);
|
|
17
17
|
static VALUE EV_suspend(VALUE self);
|
18
18
|
static VALUE EV_schedule_fiber(VALUE self, VALUE fiber, VALUE value);
|
19
19
|
|
20
|
+
static VALUE Fiber_safe_transfer(int argc, VALUE *argv, VALUE self);
|
21
|
+
|
20
22
|
static VALUE watcher_refs;
|
21
|
-
static VALUE
|
23
|
+
static VALUE next_tick_items;
|
22
24
|
|
23
|
-
static struct
|
25
|
+
static struct ev_idle next_tick_watcher;
|
24
26
|
static int next_tick_active;
|
25
|
-
void EV_next_tick_callback(ev_loop *ev_loop, struct
|
27
|
+
void EV_next_tick_callback(ev_loop *ev_loop, struct ev_idle *watcher, int revents);
|
26
28
|
|
27
29
|
VALUE EV_reactor_fiber;
|
28
30
|
VALUE EV_root_fiber;
|
@@ -58,6 +60,9 @@ void Init_EV() {
|
|
58
60
|
rb_define_global_function("snooze", EV_snooze, 0);
|
59
61
|
rb_define_global_function("next_tick", EV_next_tick, 0);
|
60
62
|
|
63
|
+
VALUE cFiber = rb_const_get(rb_cObject, rb_intern("Fiber"));
|
64
|
+
rb_define_method(cFiber, "safe_transfer", Fiber_safe_transfer, -1);
|
65
|
+
|
61
66
|
ID_call = rb_intern("call");
|
62
67
|
ID_caller = rb_intern("caller");
|
63
68
|
ID_clear = rb_intern("clear");
|
@@ -80,10 +85,10 @@ void Init_EV() {
|
|
80
85
|
watcher_refs = rb_hash_new();
|
81
86
|
rb_global_variable(&watcher_refs);
|
82
87
|
|
83
|
-
|
84
|
-
rb_global_variable(&
|
88
|
+
next_tick_items = rb_ary_new();
|
89
|
+
rb_global_variable(&next_tick_items);
|
85
90
|
|
86
|
-
|
91
|
+
ev_idle_init(&next_tick_watcher, EV_next_tick_callback);
|
87
92
|
next_tick_active = 0;
|
88
93
|
}
|
89
94
|
|
@@ -136,10 +141,10 @@ void EV_del_watcher_ref(VALUE obj) {
|
|
136
141
|
static VALUE EV_next_tick(VALUE self) {
|
137
142
|
VALUE proc = rb_block_proc();
|
138
143
|
if (RTEST(proc)) {
|
139
|
-
rb_ary_push(
|
144
|
+
rb_ary_push(next_tick_items, proc);
|
140
145
|
if (!next_tick_active) {
|
141
146
|
next_tick_active = 1;
|
142
|
-
|
147
|
+
ev_idle_start(EV_DEFAULT, &next_tick_watcher);
|
143
148
|
}
|
144
149
|
}
|
145
150
|
return Qnil;
|
@@ -149,17 +154,17 @@ static VALUE EV_snooze(VALUE self) {
|
|
149
154
|
VALUE ret;
|
150
155
|
VALUE fiber = rb_fiber_current();
|
151
156
|
|
152
|
-
rb_ary_push(
|
157
|
+
rb_ary_push(next_tick_items, fiber);
|
153
158
|
if (!next_tick_active) {
|
154
159
|
next_tick_active = 1;
|
155
|
-
|
160
|
+
ev_idle_start(EV_DEFAULT, &next_tick_watcher);
|
156
161
|
}
|
157
162
|
|
158
163
|
ret = YIELD_TO_REACTOR();
|
159
164
|
|
160
165
|
// fiber is resumed, check if resumed value is an exception
|
161
166
|
if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) {
|
162
|
-
rb_ary_delete(
|
167
|
+
rb_ary_delete(next_tick_items, fiber);
|
163
168
|
return rb_funcall(ret, ID_raise, 1, ret);
|
164
169
|
}
|
165
170
|
else {
|
@@ -187,23 +192,23 @@ VALUE EV_next_tick_runner(VALUE proc) {
|
|
187
192
|
return Qnil;
|
188
193
|
}
|
189
194
|
|
190
|
-
void EV_next_tick_callback(ev_loop *ev_loop, struct
|
191
|
-
VALUE
|
192
|
-
|
195
|
+
void EV_next_tick_callback(ev_loop *ev_loop, struct ev_idle *watcher, int revents) {
|
196
|
+
VALUE scheduled_items = next_tick_items;
|
197
|
+
next_tick_items = rb_ary_new();
|
193
198
|
|
194
|
-
|
195
|
-
|
199
|
+
long len = RARRAY_LEN(scheduled_items);
|
200
|
+
for (long i = 0; i < len; i++) {
|
201
|
+
EV_next_tick_runner(RARRAY_AREF(scheduled_items, i));
|
196
202
|
}
|
197
203
|
|
198
|
-
if
|
199
|
-
|
200
|
-
} else {
|
204
|
+
// if no next tick items were added during callback, stop the idle watcher
|
205
|
+
if (rb_array_len(next_tick_items) == 0) {
|
201
206
|
next_tick_active = 0;
|
207
|
+
ev_idle_stop(EV_DEFAULT, &next_tick_watcher);
|
202
208
|
}
|
203
209
|
}
|
204
210
|
|
205
211
|
static VALUE EV_suspend(VALUE self) {
|
206
|
-
// make sure reactor fiber is alive
|
207
212
|
if (!RTEST(rb_fiber_alive_p(EV_reactor_fiber))) {
|
208
213
|
return Qnil;
|
209
214
|
}
|
@@ -218,11 +223,20 @@ static VALUE EV_suspend(VALUE self) {
|
|
218
223
|
static VALUE EV_schedule_fiber(VALUE self, VALUE fiber, VALUE value) {
|
219
224
|
rb_ivar_set(fiber, ID_scheduled_value, value);
|
220
225
|
|
221
|
-
rb_ary_push(
|
226
|
+
rb_ary_push(next_tick_items, fiber);
|
222
227
|
if (!next_tick_active) {
|
223
228
|
next_tick_active = 1;
|
224
|
-
|
229
|
+
ev_idle_start(EV_DEFAULT, &next_tick_watcher);
|
225
230
|
}
|
226
231
|
|
227
232
|
return Qnil;
|
228
233
|
}
|
234
|
+
|
235
|
+
static VALUE Fiber_safe_transfer(int argc, VALUE *argv, VALUE self) {
|
236
|
+
VALUE arg = (argc == 0) ? Qnil : argv[0];
|
237
|
+
VALUE ret = rb_funcall(self, ID_transfer, 1, arg);
|
238
|
+
|
239
|
+
// fiber is resumed, check if resumed value is an exception
|
240
|
+
return RTEST(rb_obj_is_kind_of(ret, rb_eException)) ?
|
241
|
+
rb_funcall(ret, ID_raise, 1, ret) : ret;
|
242
|
+
}
|