在Python中存储大量数据

6 投票
3 回答
3318 浏览
提问于 2025-04-16 13:27

我先简单介绍一下我的问题。我正在写一个Python程序,用于处理不同物理模拟的后期数据。每次模拟可能会生成多达100GB的输出。我需要处理不同时间点的各种信息(比如位置、场和密度等)。我希望能一次性访问所有这些数据,但由于我的系统内存不够,这个想法实现不了。通常我会先读取文件,然后进行一些操作,再清理内存。接着再读取其他数据,进行操作,再清理内存。

现在我的问题是,如果我这样做,就会花很多时间重复读取数据。这非常耗时。我希望能只读取一次,然后存储起来,方便以后访问。你知道有什么方法可以快速存储大量数据,或者不占用太多空间吗?

我刚刚创建了一种方法,速度大约比普通的打开和读取快十倍。但我用的是cat(Linux命令)来实现。这种方法不太优雅,我想把它从我的脚本中去掉。

有没有可能使用数据库来存储这些数据,并且比正常读取更快地获取数据?(抱歉问这个问题,我不是计算机科学专业的,对数据库的知识也不多)。

编辑:

我的cat代码大概是这样的——只是一个例子:

out = string.split(os.popen("cat "+base+"phs/phs01_00023_"+time).read())
# and if I want to have this data as arrays then I normally use and reshape (if I
# need it)
out = array(out)
out = reshape(out)

通常我会使用一个numpy的方法numpy.loadtxt,它的速度和正常读取差不多:

f = open('filename')
f.read()
...

我觉得loadtxt只是用了普通的方法,加了一些额外的代码行。

我知道有一些更好的方法来读取数据,但我找到的都很慢。现在我打算试试mmap,希望能有更好的性能。

3 个回答

0

如果你在处理大数据集,Python可能不是最好的选择。如果你想使用像MySQL或Postgres这样的数据库,可以试试SQLAlchemy。它让你用小的Python对象来处理可能很大的数据集变得很简单。例如,如果你用这样的定义:

from datetime import datetime
from sqlalchemy import Column, DateTime, Enum, ForeignKey, Integer, \
    MetaData, PickleType, String, Text, Table, LargeBinary
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import column_property, deferred, object_session, \
    relation, backref

SqlaBaseClass = declarative_base()

class MyDataObject(SqlaBaseClass):
  __tablename__ = 'datarows'
  eltid         = Column(Integer, primary_key=True)
  name          = Column(String(50, convert_unicode=True), nullable=False, unique=True, index=True)
  created       = Column(DateTime)
  updated       = Column(DateTime, default=datetime.today)

  mylargecontent = deferred(Column(LargeBinary))

  def __init__(self, name):
      self.name    = name
      self.created = datetime.today()

  def __repr__(self):
      return "<MyDataObject name='%s'>" %(self.name,)

那么你就可以轻松地使用小的数据对象来访问所有的行:

# set up database connection; open dbsession; ... 

for elt in dbsession.query(MyDataObject).all():
    print elt.eltid # does not access mylargecontent

    if (something(elt)):
        process(elt.mylargecontent) # now large binary is pulled from db server
                                    # on demand

我想说的是:你可以根据需要给你的数据添加尽可能多的字段,同时添加索引来加快搜索速度。而且,最重要的是,当你使用MyDataObject时,你可以将一些可能很大的字段设置为deferred,这样它们只会在你需要的时候才加载。

7

我建议你试试 HDF5。在Python中,有两个常用的接口,分别是 h5pyPyTables。虽然后者似乎更常用,但我个人更喜欢前者。

7

如果你在使用64位的操作系统,可以利用mmap模块把整个文件映射到内存里。这样的话,读取文件中任意部分的数据会快很多,因为操作系统会帮你管理访问的方式。值得注意的是,你并不需要真的有100GB的内存来让这个方法有效,因为操作系统会在虚拟内存中处理这些数据。

我曾经在64位的FreeBSD 8系统上处理过一个30GB的文件(维基百科的XML文章转储),效果非常好。

撰写回答