String#slice! instead of buffered IO in Redis::Connection::SocketMixin#read and #gets
Redis::Connection::SocketMixin#read Redis::Connection::SocketMixin#gets abuse String#slice! and should use StringIO as better alternative of buffered read in terms of both CPU and memory. Quick test reveal a shortcoming of the existing solution:
require 'benchmark'
require 'stringio'
buffer1 = "f"*2048
buffer2 = StringIO.new(buffer1.clone)
Benchmark.bm do |x|
x.report do # for the sake of the test we should measure how long does it take to clone buffer
1000_000.times do
buffer1.clone
end
end
x.report do
1000_000.times do
# yes, we create a new string
buffer1.clone.slice!(0,1024)
end
end
x.report do
1000_000.times do
buffer2.read(1024)
buffer2.rewind
end
end
end
output
0.270000 0.000000 0.270000 ( 0.280817)
1.730000 0.550000 2.280000 ( 2.290668)
0.670000 0.190000 0.860000 ( 0.868489)
2.290668 - 0.280817 = 2.009851 (discount allocation of new strings for test purposes) 2.009851 vs 0.868489 is the significant difference.
Is this why getting the result of an sinter with 500k items takes 7 seconds without hiredis? I was a little confused, because using Ruby to parse the redis-cli response the naive way ($stdin.read.split("\n")) is quite fast.
Closing as stale since all this code was just replaced for the upcoming 5.0.