-
-
Save therealadam/4698972 to your computer and use it in GitHub Desktop.
require 'thread' | |
require 'ffaker' | |
require 'json' | |
def new_message | |
text = Faker::HipsterIpsum.sentences(3) | |
metrics = { | |
temp: rand(110), # degrees F | |
mass: rand(100), # kilograms | |
speed: rand(70) # miles per hour | |
} | |
{metrics: metrics, body: text} | |
end | |
def send_message(socket, msg) | |
encoded = JSON.dump(messages: msg) | |
socket.write(encoded) | |
end | |
FRAME_SIZE = 100 | |
if __FILE__ == $0 | |
# s = Socket.new('localhost', 4242) | |
s = $stdout | |
messages = Queue.new | |
producer = Thread.new do | |
loop do | |
messages.push(new_message) | |
end | |
end | |
begin | |
loop do | |
frame = FRAME_SIZE.times.map { messages.pop } | |
send_message(s, frame) | |
end | |
ensure | |
s.close | |
producer.join | |
end | |
end | |
Using local file /Users/adam/.rbenv/versions/1.9.3-p327-perf/bin/ruby. | |
Using local file /tmp/profile. | |
Total: 1837 samples | |
754 41.0% 41.0% 1340 72.9% Enumerable#sort_by | |
317 17.3% 58.3% 1507 82.0% Range#each | |
299 16.3% 74.6% 299 16.3% garbage_collector | |
199 10.8% 85.4% 199 10.8% Float#<=> | |
81 4.4% 89.8% 81 4.4% Kernel.rand | |
34 1.9% 91.7% 71 3.9% Array#map | |
31 1.7% 93.4% 1496 81.4% Faker::Lorem#sentence | |
15 0.8% 94.2% 1433 78.0% Module#random_pick | |
15 0.8% 95.0% 15 0.8% String#initialize_copy | |
14 0.8% 95.8% 23 1.3% Kernel#rand | |
13 0.7% 96.5% 36 2.0% Kernel#dup | |
13 0.7% 97.2% 13 0.7% String#capitalize! | |
8 0.4% 97.6% 19 1.0% Kernel#initialize_dup | |
6 0.3% 97.9% 14 0.8% Array#join | |
6 0.3% 98.3% 6 0.3% File.file? | |
5 0.3% 98.5% 1524 83.0% Object#new_message | |
4 0.2% 98.7% 4 0.2% Array#[] | |
4 0.2% 99.0% 1430 77.8% Faker::HipsterIpsum#words | |
4 0.2% 99.2% 1504 81.9% Faker::Lorem#sentences | |
\342\230\201 |
# encoding: UTF-8 | |
require 'socket' | |
require 'ffaker' | |
require 'json' | |
ZERO_LENGTH = 1024 * 8 | |
def new_message | |
text = Faker::HipsterIpsum.sentences(3) | |
random = File.read('/dev/zero', ZERO_LENGTH) | |
metrics = { | |
temp: rand(110), # degrees F | |
mass: rand(100), # kilograms | |
speed: rand(70) # miles per hour | |
} | |
{metrics: metrics, random: random, body: text} | |
end | |
def send_message(socket, msg) | |
encoded = JSON.dump(messages: msg) | |
socket.write(encoded) | |
end | |
FRAME_SIZE = 100 | |
if __FILE__ == $0 | |
s = TCPSocket.new('localhost', 4242) | |
# s = $stdout | |
begin | |
loop do | |
frame = FRAME_SIZE.times.map { new_message } | |
send_message(s, frame) | |
end | |
ensure | |
s.close | |
end | |
end | |
require 'ffaker' | |
require 'json' | |
def new_message | |
text = Faker::HipsterIpsum.sentences(3) | |
metrics = { | |
temp: rand(110), # degrees F | |
mass: rand(100), # kilograms | |
speed: rand(70) # miles per hour | |
} | |
{metrics: metrics, body: text} | |
end | |
def send_message(socket, msg) | |
encoded = JSON.dump(messages: msg) | |
socket.write(encoded) | |
end | |
FRAME_SIZE = 100 | |
if __FILE__ == $0 | |
# s = Socket.new('localhost', 4242) | |
s = $stdout | |
begin | |
loop do | |
frame = FRAME_SIZE.times.map { new_message } | |
send_message(s, frame) | |
end | |
ensure | |
s.close | |
end | |
end | |
Using local file /Users/adam/.rbenv/versions/1.9.3-p327-perf/bin/ruby. | |
Using local file /tmp/profile. | |
Total: 947 samples | |
370 39.1% 39.1% 725 76.6% Enumerable#sort_by | |
195 20.6% 59.7% 818 86.4% Range#each | |
118 12.5% 72.1% 118 12.5% Float#<=> | |
64 6.8% 78.9% 64 6.8% garbage_collector | |
43 4.5% 83.4% 43 4.5% Kernel.rand | |
23 2.4% 85.9% 23 2.4% IO#write | |
13 1.4% 87.2% 13 1.4% Array#join | |
12 1.3% 88.5% 26 2.7% Kernel#dup | |
11 1.2% 89.7% 37 3.9% Array#map | |
11 1.2% 90.8% 816 86.2% Faker::Lorem#sentence | |
10 1.1% 91.9% 10 1.1% String#initialize_copy | |
9 1.0% 92.8% 10 1.1% Kernel#rand | |
7 0.7% 93.6% 15 1.6% JSON::Ext::Generator::State#generate | |
6 0.6% 94.2% 10 1.1% Kernel#eval | |
6 0.6% 94.8% 774 81.7% Module#random_pick | |
6 0.6% 95.5% 829 87.5% Object#new_message | |
6 0.6% 96.1% 6 0.6% String#capitalize! | |
5 0.5% 96.6% 779 82.3% Faker::ArrayUtils#random_pick | |
4 0.4% 97.0% 4 0.4% Range.allocate | |
\342\230\201 |
Did you actually run this with the commented out socket line, instead of just $stdout
? Was the performance profile pretty much that same?
I wouldn't expect a big gain here.
You are just using two threads, one for building messages and one for sending. The only potential sleep time is when you write to the IO. So, in that one small window, that thread might sleep and allow some message creation.
However, you introduced a fair bit of infrastructure to get just this far. Threads have to be spun up and time sliced, plus we have enqueuing and dequeuing overhead. You are clearly paying a price for that.
One thought is that the price paid is just higher than any small gain achieved. Another possibility is that the GIL interaction with $stdout
is tricky. I think those are my best two ideas.
Have you tried it on JRuby, where some real concurrency might be achievable?
I apologize if none of this helps. I'm not a threading pro and I'm mostly just thinking out loud.
@JEG2 I didn't do anything beyond profiling it to see if the bottleneck was different. I think I should only have two threads: one for producing messages, and another for IO. IF I was IO-bound, I believe this would effectively circumvent the GIL. However, I'm clearly bound on generating ipsum text.
FWIW, I introduced framing/batching messages because without it the producer was painfully slow.
I added threads on a lark to see if it was marginally faster. My surprise is how much slower it is.
@JEG2 check out lolput.rb. I cheated and got a lot closer to my baseline benchmark. On my laptop, this produces does about 75-78 MB/s of throughput:
# Producer
$ cat /dev/zero | nc localhost 4242
# Consumer
$ nc localhost 4242 | pv > /dev/null
lolput.rb does 42-45 MB/s. It's now much closer to my baseline. Generating a string of zeroes in the kernel is FAST guys!
Judging by the similarities of the profiles, I think both are bottlenecking around ffaker, but the threaded version has some contention that isn't jumping out at me.
Note this is test harness for spewing data (relatively) quickly with Ruby alone, so it doesn't need to be rocket scienced.