polyphony 0.17 → 0.19
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|