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

Python中数字数据到固定宽度格式文件的快速转换,python,performance,large-data-volumes,Python,Performance,Large Data Volumes,将仅包含数字数据的记录转换为固定格式字符串并将其写入Python文件的最快方法是什么?例如,假设record是一个庞大的列表,由具有属性id、x、y和wt的对象组成,我们经常需要将它们刷新到外部文件中。可以使用以下代码段进行刷新: 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)) 然而

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

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,它仍然消耗相同的核心。我想我可以把它转移到完全独立的过程

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

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

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

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

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

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

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

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

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

如果您使用数据库思想,请尝试使用PostgreSQL。它是免费的,而且是一个真正的数据库。要将数据库与Python一起使用,应该使用ORM。其中最好的是炼金术

另一件需要考虑的事情是:如果您以固定宽度的文本文件格式保存数据,以便将来在另一个应用程序中解析和使用数据,并且如果该应用程序既可以读取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核之间工作的好方法


现在我没有主意了。

既然你更新了你的问题,我对你面临的问题有了一个稍微好一点的了解

我不知道什么是“当前的数据库解决方案,它被认为太慢和麻烦”,但我仍然认为,如果使用得当,数据库会有所帮助

运行Python代码收集数据,并使用ORM模块将数据插入/更新到数据库中。然后运行一个单独的进程生成一个“报告”,即固定宽度的文本文件。数据库将完成生成文本文件的所有工作。
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)
$ 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