зеркало из https://github.com/github/bert.git
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:
Родитель
dd6090ef65
Коммит
2983829c66
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче