Python中数值数据到定宽格式文件的快速转换

2024-04-24 15:14:12 发布

您现在位置:Python中文网/ 问答频道 /正文

将只保存数字数据的记录转换为固定格式字符串并将其写入Python文件的最快方法是什么?例如,假设record是一个由具有idxy和{}属性的对象组成的庞大列表,我们经常需要将它们刷新到外部文件中。可以使用以下代码段完成刷新:

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))

然而,我的代码在生成外部文件上花费了太多的时间,而在两次刷新之间留给它的时间太少了。在

修改原问题:

我在编写一个服务器软件时遇到了这个问题,该软件通过从几个“生产者”系统中提取信息来跟踪一个全局记录集,并将对记录集的任何更改以预处理的形式实时或接近实时地传递给“消费者”系统。许多消费系统都是Matlab应用程序。在

我在下面列出了到目前为止收到的一些建议(谢谢),并提出了一些意见:

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

Tags: 文件数据方法字符串代码id数据库进程
3条回答

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

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

您是定期保存所有数据,还是仅保存更改的数据?如果您正在处理一个非常大的数据集,只更改一些数据,并写入所有数据。。。我们可以从这个角度来解决你的问题。在

如果你有一个大的数据集,你想不时地更新它。。。你是数据库的候选人。一个真正的数据库,用C语言编写以提高速度,它将允许您向它抛出大量的数据更新,并使所有记录保持一致的状态。然后,您可以每隔一段时间运行一个“报告”,从中提取记录并写入固定宽度的文本文件。在

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

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

如果您的进一步处理也是在Python中进行的,那么您可以将数据永远保留在数据库中。不必费心通过固定宽度的文本文件往返数据。我假设您使用的是固定宽度的文本文件,因为很容易再次提取数据以备将来处理。在

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

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

除上述之外,我唯一的另一个想法是将程序分成“worker”部分和“updater”部分,worker在其中生成更新的记录,updater部分将记录保存到磁盘。也许让他们通过让工人以文本格式将更新的记录放入标准输出进行通信;让更新程序从标准输入中读取并更新其数据记录。与SQL数据库不同,更新程序可以使用字典来存储文本记录;当新记录到达时,它可以简单地更新字典。像这样:

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

实际上,您可以让更新程序保留两个字典,并在另一个字典写入磁盘时继续更新其中一个。在

划分为worker和updater是确保worker不会花费所有时间更新的好方法,也是在多个CPU内核之间平衡工作的一个好方法。在

我现在没主意了。在

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

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

我试图检查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.4ghz核心双核macbookpro上,使用macosx10.5.8,python2.5.4从DMG开始)python.org网站,numpy 1.4 rc1(根据源代码构建)有点令人惊讶,但它们非常可重复,因此我认为它们可能会引起兴趣:

^{pr2}$

因此,savetxt似乎比循环调用write慢几个百分点。。。但是好的旧的print(也在循环中)似乎比write快几个百分点(我想这是为了避免某种呼叫开销)。我意识到2.5%左右的差距不是很重要,但这并不是我直觉所期望的方向,所以我想我应该报告一下。(顺便说一句,使用一个真正的文件而不是/dev/null只会均匀地增加6到7毫秒,所以它不会以任何方式改变很多事情)。在

相关问题 更多 >