所以我正在编写这个程序来创建曼德尔布罗集的图片,并且我一直在逐步使其变得更好。现在,生成的每个进程都会将一些数据写入临时文件,稍后将使用该文件将图片放在一起。然而,现在临时文件比实际图片本身大得多,我对如何缩小它们没有任何想法。如何有效地将整数数据写入文件并将其取回?我打算最终使其具有很好的可扩展性,因此我需要能够为像素索引编写任意长的整数,但颜色数据始终是三个整数,最大值为 255。这是我的代码:
import multiprocessing
def pixproc(y0, yn, xsteps, ysteps, fname):
XMIN, YMIN = -2., -1.
XLEN, YLEN = 3, 2
with open(fname, 'w') as f:
for y in xrange(y0, yn):
print y
for x in xrange(xsteps):
c=complex(XMIN + XLEN*(1.*x/xsteps),
YMIN + YLEN*(1.*y/ysteps))
k=c
for i in xrange(256):
k = k*k + c
if abs(k)>2: break
if 0<i<32:
#print 'Success!', i
print >>f, x, y, 8*i, 0, 0 #This is that part of
if 32<=i<255: #my code that I am trying
#print 'Success!', i #to improve. The rest of
print >>f, x, y, 255, i, i #the code is given for context
return #and isn't relevant to my question
def main(xsteps, ysteps):
pool = multiprocessing.Pool()
n = multiprocessing.cpu_count()
step = height / n
fnames = ["temp" + str(i) for i in xrange(n)]
for i in xrange(n):
pool.apply_async(pixproc,
(step*i,
step*(i+1),
xsteps,
ysteps,
fnames[i]))
pool.close()
pool.join()
return fnames
if __name__=="__main__":
from PIL import Image
import sys
width, height = map(int, sys.argv[1:])
picname = "mandelbrot1.png"
fnames = main(width, height)
im = Image.new("RGB", (width, height))
pp = im.load()
for name in fnames:
with open(name) as f:
for line in f:
line = map(int, line.rstrip('\n').split(' '))
pp[line[0], line[1]] = line[2], line[3], line[4]
im.save(picname)
当我尝试制作一张3000x2000的图片时,实际图片是672 KB,但临时文件都接近30 MB!有人可以建议一种更好的方法将数据存储在文件中吗? (重要的部分在pixproc函数中)
最佳答案
假设您只是想消除对临时数据使用基于文本的格式而不是二进制格式的开销,并且您不想重写所有内容以使用 numpy,那么有几种不同的解决方案:
<小时/>首先,可以先将数据保存为二进制格式:mmap
文件,然后使用 ctypes
将其视为某种巨大的记录。这通常带来的麻烦大于其值(value),但值得一提。
假设您的数据只不过是一长串 5 字节的元组:
class Entry(ctypes.Structure):
_fields_ = [("x", ctypes.c_uint8), ("y", ctypes.c_uint8),
("i", ctypes.c_uint8), ("j", ctypes.c_uint8), ("k", ctypes.c_uint8)]
Entries = ctypes.POINTER(Entry)
with open(fname, 'wb') as f:
f.truncate(ctypes.sizeof(Entry * (yn - y0)))
m = mmap.mmap(f.fileno(), access=mmap.ACCESS_WRITE)
<小时/>
其次,您可以使用struct
。您必须阅读文档才能获得完整的详细信息,但我将举一个例子。让我们看一下这一行:
print >>f, x, y, 8*i, 0, 0
现在,我们假设所有 5 个都保证是字节 (0-255)。你可以这样做:
f.write(struct.pack('BBBBB', x, y, 8*i, 0, 0))
稍后再读:
x, y, i8, 0, 0 = struct.unpack('BBBBB', f.read(struct.calcsize('BBBBB')))
i = i8//8
如果它们中的任何一个需要长于一个字节,则需要处理字节顺序,但这非常简单。例如,如果 x
和 y
范围从 -32768 到 32767:
f.write(struct.pack('>hhBBB', x, y, 8*i, 0, 0))
并确保以二进制模式打开文件。
如果您愿意,您当然可以将其与 mmap
结合使用,这意味着您可以只使用 struct.pack_into
和 struct.unpack_from
> 而不是显式使用 pack
加 write
和 unpack
加 read
。
接下来是pickle
。要么直接创建列表,然后 pickle.dump
它,或者手动 pickle.dumps
每个条目并在其上方添加一些简单的高级结构(或者只使用 shelve
,如果该更高级别的结构是或可能是从键到条目的简单映射)。这可能会更大而不是更小,而且可能会更慢,因此在考虑这一点之前您总是希望进行一些测试。但有时这是一个简单的解决方案。
最后,您可能可以想出一种更紧凑的文本格式,而不仅仅是打印每个对象的 str
表示形式。这通常不值得付出努力,但同样值得考虑。
关于python - 如何制作较小的临时文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15911013/