introduce a new buffered writer method

This method will buffer writes, but to an array rather than to a
StringIO.  This allows us to calculate the size of the BERT packet that
we're going to send *without* copying large strings in to a new buffer.
Writes might take a bit more CPU, but will take fare less memory.
This commit is contained in:
Aaron Patterson 2016-05-20 11:19:30 -07:00
Родитель dd6090ef65
Коммит 2983829c66
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 953170BCB4FFAFC6
5 изменённых файлов: 77 добавлений и 4 удалений

29
bench/memsize.rb Normal file
Просмотреть файл

@ -0,0 +1,29 @@
require 'bert'
require 'objspace'
large = ["abc" * 1000] * 10000
def write_berp(output, ruby)
data = BERT.encode(ruby)
output.write([data.bytesize].pack("N"))
output.write(data)
end
def write_berp2(output, ruby)
data = BERT.encode_to_buffer(ruby)
output.write([data.bytesize].pack("N"))
data.write_to output
end
socket = File.open File::NULL, 'wb' do |f|
GC.start; GC.start; GC.start; GC.disable
before = ObjectSpace.memsize_of_all(String)
write_berp f, large
p :ORIGINAL => ObjectSpace.memsize_of_all(String) - before
GC.start; GC.start; GC.start; GC.disable
before = ObjectSpace.memsize_of_all(String)
write_berp2 f, large
p :NEW => ObjectSpace.memsize_of_all(String) - before
end

Просмотреть файл

@ -3,6 +3,10 @@ module BERT
Encoder.encode(ruby)
end
def self.encode_to_buffer(ruby)
Encoder.encode_to_buffer(ruby)
end
def self.decode(bert)
Decoder.decode(bert)
end
@ -18,4 +22,4 @@ module BERT
"t#{super}"
end
end
end
end

Просмотреть файл

@ -49,17 +49,44 @@ module BERT
self.out = out
end
class Buffer
def initialize
@buf = []
end
def write(str)
@buf << str
end
def write_to(io)
@buf.each { |x| io.write x }
end
def bytesize
@buf.map(&:bytesize).inject :+
end
end
def self.encode_to_buffer(data)
io = Buffer.new
encode_data data, io
io
end
def self.encode(data)
buf = encode_to_buffer data
io = StringIO.new
io.set_encoding('binary') if io.respond_to?(:set_encoding)
buf.write_to io
io.string
end
def self.encode_data(data, io)
if version == :v2
Encode::V2.new(io).write_any(data)
else
new(io).write_any(data)
end
io.string
end
def write_any obj

Просмотреть файл

@ -9,6 +9,11 @@ module BERT
Encode.encode(complex_ruby)
end
def self.encode_to_buffer(ruby)
complex_ruby = convert(ruby)
Encode.encode_to_buffer(complex_ruby)
end
# Convert complex Ruby form in simple Ruby form.
# +item+ is the Ruby object to convert
#
@ -42,4 +47,4 @@ module BERT
end
end
end
end
end

Просмотреть файл

@ -44,6 +44,14 @@ class BertTest < Test::Unit::TestCase
assert_equal @bert, BERT.encode(@ruby)
end
should "encode with buffer" do
buf = BERT.encode_to_buffer(@ruby)
io = StringIO.new
io.set_encoding 'binary'
buf.write_to io
assert_equal @bert, io.string
end
should "ebin" do
assert_equal @ebin, BERT.ebin(@bert)
end