【问题标题】:How to accelerate reads from batches of files如何加速批量文件的读取
【发布时间】:2011-04-21 15:02:09
【问题描述】:

我从我的系统中读取了许多文件。我想更快地阅读它们,可能是这样的:

results=[]
for file in open("filenames.txt").readlines():
    results.append(open(file,"r").read())

我不想使用线程。任何建议表示赞赏。

我不想使用线程的原因是因为它会使我的代码不可读,我想找到一种棘手的方法来提高速度,减少代码,更容易理解

昨天我测试了另一种多处理解决方案,效果不好,我不知道为什么, 代码如下:

def xml2db(file):
    s=pq(open(file,"r").read())
    dict={}
    for field in g_fields:
        dict[field]=s("field[@name='%s']"%field).text()
    p=Product()
    for k,v in dict.iteritems():
        if v is None or v.strip()=="":
            pass
        else:
            if hasattr(p,k):
                setattr(p,k,v)
    session.commit()
@cost_time
@statistics_db
def batch_xml2db():
    from multiprocessing import Pool,Queue
    p=Pool(5)
    #q=Queue()
    files=glob.glob(g_filter)
    #for file in files:
    #    q.put(file)

    def P():
        while q.qsize()<>0:
            xml2db(q.get())
    p.map(xml2db,files)
    p.join()

【问题讨论】:

  • 所以你想在不使用线程的情况下比平时更快地阅读它?任何程序每个线程一次只能做一件事。
  • @dutt:实际上,可以通过使用 Windows 中的重叠 I/O 和 Linux 中的 AIO(我认为支持不佳)等机制来更快地让操作系统重新排序读取以匹配磁盘布局和减少寻道。不过,我严重怀疑他是否真的想这样做。它要复杂得多,而且不会总是有很大的不同。
  • 重叠的 i/o...整洁。你每天都会学到一些东西。
  • @dutt 我不想使用线程的原因是因为它会使我的代码不可读,我想找到如此棘手的方法来提高速度和减少代码,更容易理解
  • 你的意思是“我不想使用线程的原因是因为它会使我的代码不可读,我想找到一些棘手的方法来制作程序更快,代码行更少,并且更容易理解”?目前,这句话在结尾处分崩离析。 WRT 线程代码不可读 - 这是有争议的。有一些高级构造使线程代码非常易读,还有一些用于传统线程 API 的简单组织技术。

标签: python performance file concurrency io


【解决方案1】:
results = [open(f.strip()).read() for f in open("filenames.txt").readlines()]

这可能会稍微快一点,但它可能不太可读(取决于读者对列表推导的熟悉程度)。

您的主要问题是磁盘 IO 是瓶颈 - 购买更快的磁盘比修改您的代码产生的影响要大得多。

【讨论】:

  • 它将成本时间从 805s 减少到 714s,谢谢,但我仍然想找到更快的方法,我也想知道为什么这种样式会比我的代码更快
  • @mlzboy,如果你有这么大的加速,你一定有很多小文件。这段代码在函数内部吗?这也可以加快速度。
  • 这更快,因为循环是作为列表理解的一部分处理的,这很可能在本机代码中而不是解释的 Python 中。如果没有线程,你不可能比这更快(使用 Python)。磁盘 IO 仍然是你的瓶颈。
【解决方案2】:

好吧,如果你想提高性能,那就改进算法吧?你用这些数据做什么?你真的需要同时在内存中,如果filenames.txt指定的文件太多或太大,可能会导致OOM?

如果您使用大量文件执行此操作,我怀疑您正在颠簸,因此您需要 700 秒以上(1 小时以上)的时间。即使是我可怜的小 HD 也能维持 42 MB/s 的写入速度(42 * 714s = 30GB)。知道您必须读写,但我猜您没有超过 8 GB 的 RAM 可用于此应用程序。 A related SO question/answer 建议您使用 mmap,上面的答案建议使用迭代/惰性读取,就像您在 Haskell 中免费获得的一样。如果您确实有数十 GB 的容量可供使用,那么这些可能值得考虑。

【讨论】:

    【解决方案3】:

    这是一次性要求还是您需要定期做的事情?如果这是您经常要做的事情,请考虑使用 MySQL 或其他数据库而不是文件系统。

    【讨论】:

    • 我从 html 中提取数据并持久化到许多 xml 文件中,然后我将 xml 放到 mysql 数据库中
    • 啊,那我想你会得到更大的好处,直接从html到xml直接到数据库,而不需要写入文件系统的中间步骤。这样可以节省写入和读取。或者,将您的 xml 文件放在您的网络服务器下并通过套接字读取它们,而不是调用操作系统文件系统。
    【解决方案4】:

    不确定这是否仍然是您正在使用的代码。 我会考虑进行一些调整。

    原文:

    def xml2db(file):
        s=pq(open(file,"r").read())
        dict={}
        for field in g_fields:
            dict[field]=s("field[@name='%s']"%field).text()
        p=Product()
        for k,v in dict.iteritems():
            if v is None or v.strip()=="":
                pass
            else:
                if hasattr(p,k):
                    setattr(p,k,v)
        session.commit()
    

    更新: 去掉dict的使用,就是额外的对象创建、迭代和收集。

    def xml2db(file):
        s=pq(open(file,"r").read())
    
        p=Product()
        for k in g_fields:
            v=s("field[@name='%s']"%field).text()
            if v is None or v.strip()=="":
                pass
            else:
                if hasattr(p,k):
                    setattr(p,k,v)
        session.commit()
    

    您可以使用 python 分析器分析代码。

    这可能会告诉您花费的时间在哪里。 它可能在 session.Commit() 中,这可能需要减少到每两个文件。

    我不知道它做了什么,所以这真的是在黑暗中刺伤,你可以尝试运行它而不发送或写入任何输出。

    如果您可以将代码分为阅读、处理和写作。 A) 你可以看到读取所有文件需要多长时间。

    然后通过将单个文件加载到内存进程中,它有足够的时间来表示整个作业,而无需额外的读取 IO。 B) 处理成本

    然后保存一大堆代表您的工作规模的会话。 C) 输出成本

    单独测试每个阶段的成本。这应该会告诉你什么是花费最多的时间,以及是否可以在任何领域做出任何改进。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-10
      • 1970-01-01
      • 2018-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-25
      相关资源
      最近更新 更多