如何在Ruby和Python之间传输基本对象?
目前,我正在使用JSON作为一种数据格式,把一个简单的包含字符串、数字和数组的哈希表从Ruby传输到Python脚本中:
IO.popen('./convert.py', 'w') do |w|
w.write({ :height => height, :width => width, :id => job_id, :data => pix }.to_json)
w.write "\n"
w.close_write
end
在这个例子中,height
、width
和job_id
都是数字,而pix
是一个包含整数数组的数组。
这个Python脚本的内容是:
#!/usr/bin/env python
from PIL import Image
import json
import sys
output = json.load(sys.stdin)
width = output['width']
height = output['height']
name = 'images/' + str(output['id']) + '/image.bmp'
data = [ tuple(datum) for datum in output['data'] ]
img = Image.new("RGB", (width, height))
img.putdata(data)
img.save(name)
我做了一些快速测试,使用了一个有390万个值的数组(大约是正常使用大小的四分之一),结果发现这个脚本运行大约需要105秒。如果把output = ...
下面的所有行注释掉,运行时间会缩短到90秒。显然,对于这样一个简单的脚本,如果序列化的过程不占用85%的处理时间,那就太好了。
我能想到的唯一加速方法,就是找一种二进制序列化/封装的方法,能够用来把数据从Ruby传输到Python。不过,我没有找到这样的系统,只有一个叫RMarshal的工具,它似乎只能反向工作。
2 个回答
2
看起来生成和(特别是)解析JSON的过程是可以改进的,因为使用一个简单的自定义格式就能带来很大的不同,而不需要使用非文本格式。我不得不改变你使用的putdata方法(特别是传入的数据格式),否则下面的测试结果就不会有显著的差别。
$ time ./gen-json.py 1500 900 json | ./read-json.py
real 0m50.727s
user 0m50.131s
sys 0m0.164s
$ time ./gen.py 1500 900 custom | ./read.py
real 0m3.786s
user 0m6.076s
sys 0m0.064s
请原谅这些代码的粗糙,因为它们是在大约5分钟内写的,目的是为了开始找出问题可能出在哪里。不过,在这些代码中一切似乎都正常;至少我可以打开生成的BMP文件。:)
gen-json.py
#!/usr/bin/env python2.6
import sys
width, height, img_id = sys.argv[1:]
width = int(width)
height = int(height)
print """{"width": %s, "height": %s, "id": "%s", "data": [""" % (width, height, img_id)
row = str([0 for _ in xrange(width)])
first = True
for _ in xrange(height):
if first:
first = False
else:
print ","
print row,
print "]}"
read-json.py
#!/usr/bin/env python2.6
import json
import sys
from PIL import Image
output = json.load(sys.stdin)
width = output['width']
height = output['height']
name = 'image-%s.bmp' % output['id']
data = []
assert len(output['data']) == height
for x in output['data']:
assert len(x) == width
data.extend(x)
img = Image.new("RGB", (width, height))
img.putdata(data)
img.save(name)
gen.py
#!/usr/bin/env python2.6
import sys
width, height, img_id = sys.argv[1:]
width = int(width)
height = int(height)
print img_id, width, height
for _ in xrange(height):
for _ in xrange(width):
print 0,
print
read.py
#!/usr/bin/env python2.6
import sys
from PIL import Image
img_id, width, height = raw_input().split()
width = int(width)
height = int(height)
name = "image-%s.bmp" % img_id
data = [int(x) for row in sys.stdin for x in row.split()]
assert len(data) == width * height
img = Image.new("RGB", (width, height))
img.putdata(data)
img.save(name)
9
也许可以试试MessagePack。它支持多种编程语言,包括Ruby和Python。