2009-12-06 70 views
3

将只保留数字数据的记录转换为固定格式字符串并将它们写入Python文件中的最快方式是什么?例如,假设record是一个包含属性为id,x,ywt的对象的巨大列表,我们经常需要将它们刷新到外部文件。冲洗可以用下面的代码片段来完成:将数值数据快速转换为Python中的固定宽度格式文件

with open(serial_fname(), "w") as f: 
    for r in records: 
     f.write("%07d %11.5e %11.5e %7.5f\n" % (r.id, r.x, r.y, r.wt)) 

但是我的代码是花费了太多的时间产生外部文件中留下太少时间做什么是应该的冲洗之间的事。

Amendmend原来的问题:

我就遇到了这个问题,同时编写跟踪拉几个“生产者”系统信息设置一个全球性的记录,并转发到任何更改的服务器软件以预处理的形式实时或接近实时地记录到“消费者”系统。许多消费者系统都是Matlab应用程序。

我在下面列出了一些建议,我有一些评论到目前为止(感谢)获得:

  • 只输出变化,而不是整个数据集:我其实已经在做。由此产生的变化集仍然很大。
  • 使用二进制(或其他一些更有效的)文件格式:我几乎由什么Matlab的能合理高效,除了该格式应该是独立于平台的读取限制。
  • 使用数据库:我实际上试图绕过当前的数据库解决方案,它被认为既缓慢又麻烦,尤其是在Matlab方面。
  • 将任务划分为单独的进程:目前转储代码正在其自己的线程中运行。但是由于GIL,它仍然在使用相同的核心。我想我可以把它移到完全独立的进程。

回答

0

您可以尝试在内存中构建所有输出字符串,例如使用长字符串。 ,然后在文件中写入这个长字符串。

更快: 您可能想使用二进制文件而不是文本文件来记录信息。但是,那么你需要编写另一个工具来查看二进制文件。

2

我没有看到任何关于您可以真正优化的代码段。所以,我认为我们需要做一些完全不同的事情来解决你的问题。

你的问题似乎是你正在咀嚼大量数据,并且将数据格式化为字符串并将字符串写入文件的速度很慢。你说“冲洗”,这意味着你需要定期保存数据。

您是否经常保存的数据或仅更改了数据?如果你正在处理一个非常大的数据集,改变一些数据,并写出所有的数据......这是一个我们可以攻击的角度来解决你的问题。

如果你有一个大的数据集,并且你想不时地更新它......你是一个数据库的候选人。一个真正的数据库,用C编写的速度,可以让你在它上面扔大量的数据更新,并保持所有的记录处于一致的状态。然后你可以每隔一段时间运行一个“报告”,它将拉动记录并从中写入固定宽度的文本文件。

换句话说,我建议您将问题分为两部分:在您计算或接收更多数据时逐渐更新数据集,并将整个数据集转储为固定宽度的文本格式,以供您进一步研究处理。

请注意,您实际上可以从数据库生成文本文件,而无需停止正在更新它的Python进程。你会得到一个不完整的快照,但如果记录是独立的,那应该没问题。

如果你的进一步处理也是在Python中,你可以永远留在数据库中的数据。不要打扰通过固定宽度的文本文件来回转数据。我假设你使用的是固定宽度的文本文件,因为很容易再次提取数据以供将来处理。

如果您使用数据库的想法,请尝试使用PostgreSQL。它是免费的,它是一个真正的数据库。为了在Python中使用数据库,您应该使用ORM。最好的之一是SqlAlchemy。

另一件需要考虑的事情是:如果您将数据保存为固定宽度的文本文件格式,以便将来解析和使用其他应用程序中的数据,并且该应用程序可以读取JSON以及固定宽度,你可以使用一个写JSON的C模块。它可能不会更快,但它可能;你可以通过基准测试来看看。

除了上述内容,我唯一的想法是将程序拆分为“工作”部分和“更新程序”部分,其中工作人员生成更新记录,更新程序部分将记录保存到磁盘。或许让他们通过让工作人员以文本格式将更新的记录放到标准输出中进行交流;并使更新程序从标准输入读取并更新其数据记录。更新程序可以使用字典来存储文本记录,而不是SQL数据库;当新的到达时,它可以简单地更新字典。这样的事情:

for line in sys.stdin: 
    id = line[:7] # fixed width: id is 7 wide 
    records[id] = line # will insert or update as needed 

你实际上可以让updater保留两个字典,并保持更新一个,而另一个写出到磁盘。

划分为工作者和更新者是确保工作人员不会花费全部时间更新的好方法,也是平衡跨多个CPU核心工作的好方法。

我现在没有想法。

0

现在你已经更新了你的问题,我对你面临的问题有了一个更好的想法。

我不知道“当前的数据库解决方案既慢又笨”,但我仍认为如果正确使用数据库将会有所帮助。

运行Python代码来收集数据,并使用ORM模块将数据插入/更新到数据库中。然后运行一个单独的进程来创建一个“报告”,这将是固定宽度的文本文件。数据库会做全部生成你的文本文件的工作。如果有必要,将数据库放在自己的服务器上,因为现在硬件相当便宜。

3

我是想检查是否numpy.savetxt可能加速了一点东西,所以我写了下面的仿真:

import sys 
import numpy as np 

fmt = '%7.0f %11.5e %11.5e %7.5f' 
records = 10000 

np.random.seed(1234) 
aray = np.random.rand(records, 4) 

def writ(f, aray=aray, fmt=fmt): 
    fw = f.write 
    for row in aray: 
    fw(fmt % tuple(row)) 

def prin(f, aray=aray, fmt=fmt): 
    for row in aray: 
    print>>f, fmt % tuple(row) 

def stxt(f, aray=aray, fmt=fmt): 
    np.savetxt(f, aray, fmt) 

nul = open('/dev/null', 'w') 
def tonul(func, nul=nul): 
    func(nul) 

def main(): 
    print 'looping:' 
    loop(sys.stdout, aray) 
    print 'savetxt:' 
    savetxt(sys.stdout, aray) 

我发现的结果(在我的2.4 GHz的Core Duo处理器的MacBook Pro,与Mac OS X 10.5 2.8,Python的2.5.4从DMG上python.org,numpy的1.4 RC1来源建)略微令人吃惊,但他们具有相当的可重复的,所以我认为他们可能感兴趣的:

$ py25 -mtimeit -s'import ft' 'ft.tonul(ft.writ)' 
10 loops, best of 3: 101 msec per loop 
$ py25 -mtimeit -s'import ft' 'ft.tonul(ft.prin)' 
10 loops, best of 3: 98.3 msec per loop 
$ py25 -mtimeit -s'import ft' 'ft.tonul(ft.stxt)' 
10 loops, best of 3: 104 msec per loop 

如此,savetxt似乎是几个百分点较慢比一个循环调用write ...但好老print(也在一个循环中)似乎是几个百分点更快write(我想这是避免某种调用开销)。我意识到2.5%左右的差距并不是很重要,但它不是我直觉上预期的方向,所以我想我会报告它。 (顺便说一句,使用真正的文件,而不是/dev/null只能统一增加6或7毫秒,所以它不会改变很多,这种或那种方式)。

0

你可以尝试使用ctypes将你的循环推向C语言。

相关问题