【问题标题】:What is the fastest/most efficient way to loop through a large collection of files and save a plot of the data?循环浏览大量文件并保存数据图的最快/最有效方法是什么?
【发布时间】:2014-05-09 19:43:25
【问题描述】:

所以我有这个程序循环通过大约 2000 多个数据文件,执行傅立叶变换,绘制变换,然后保存图形。感觉程序运行的时间越长,它似乎就越慢。有没有办法通过对下面的代码进行简单的更改来让它运行得更快或更干净?

以前,我将傅立叶变换定义为一个函数,但我在这里读到 python 的函数调用开销很高,所以我取消了该函数,现在直接运行。另外,我读到clf() 有一个稳定的以前数字的日志,如果你遍历很多图,可能会变得非常大并减慢进程,所以我将其更改为close()。这些好的变化也体现在哪里?

from numpy import *
from pylab import *

for filename in filelist:

    t,f = loadtxt(filename, unpack=True)

    dt = t[1]-t[0]
    fou = absolute(fft.fft(f))
    frq = absolute(fft.fftfreq(len(t),dt))

    ymax = median(fou)*30

    figure(figsize=(15,7))
    plot(frq,fou,'k')

    xlim(0,400)
    ylim(0,ymax)

    iname = filename.replace('.dat','.png')
    savefig(iname,dpi=80)
    close()

【问题讨论】:

  • 在这种情况下,Python 的开销将完全微不足道——你的大部分时间将花在 numpy/pylab 调用上——这将被委派给高效的低级代码- 这似乎只是您正在执行的昂贵操作的一个案例。
  • 这与您的问题没有直接关系,但总的来说,from <module> import * 并不是一个好主意。这使得您很难判断您正在调用的函数是在哪里定义的,并且可能会导致您不知道的函数名称之间发生冲突。
  • @Lattyware 是的,文件大小不一,从几 Mb 到几十 Mb,因此傅立叶变换可能非常密集。我只是不确定改变一些绘图功能是否会有所帮助。
  • @dano 哦,是的,别担心,我的代码中没有这样做。输入它比写出我导入的每个函数更容易:)
  • pylab是个坏主意,直接从numpymatplotlib.pyplot导入(而pyplot对脚本来说不是个好主意,直​​接使用OO接口)。

标签: python matplotlib fft figure


【解决方案1】:

您是否考虑过使用multiprocessing 模块来并行处理文件?假设您实际上是 CPU 密集型的(这意味着傅立叶变换占用了大部分运行时间,而不是读取/写入文件),这应该会加快执行时间,而实际上不需要加速循环本身。

编辑:

例如,像这样的东西(未经测试,但应该给你的想法):

def do_transformation(filename)
    t,f = loadtxt(filename, unpack=True)

    dt = t[1]-t[0]
    fou = absolute(fft.fft(f))
    frq = absolute(fft.fftfreq(len(t),dt))

    ymax = median(fou)*30

    figure(figsize=(15,7))
    plot(frq,fou,'k')

    xlim(0,400)
    ylim(0,ymax)

    iname = filename.replace('.dat','.png')
    savefig(iname,dpi=80)
    close()

pool = multiprocessing.Pool(multiprocessing.cpu_count())
for filename in filelist:
    pool.apply_async(do_transformation, (filename,))
pool.close()
pool.join()

您可能需要调整工作进程中实际完成的工作。例如,尝试并行化磁盘 I/O 部分可能对您没有多大帮助(甚至伤害您)。

【讨论】:

  • 嗯。你能详细说明一下吗?我对这个程序有点时间紧张。似乎以我的速度,看起来还要再过一两天才能完成,而且我真的要拍摄 12-18 小时。
  • 我刚刚选择了您的评论作为答案,因为它有效地将程序加速了近 8 倍(cpu 的数量)。但如果可以的话,我还有一个问题。这里有一些文件非常大,需要很长时间才能处理。有没有办法将多个处理器分配给同一个任务,而不是将它们应用于单独的文件?
  • 没有简单的调整可以说“在这个任务中投入更多的 CPU”。您需要重构代码以将您的工作方法分解为多个进程可以同时处理的较小部分,然后在所有部分准备就绪后将其重新组合在一起。例如,看起来fou = absolute(...frq = absolute(... 可以并行计算。但是您必须小心,因为在进程之间传递大量数据可能会很慢。我很难确切地说出你可以做出什么样的改变,因为我真的不明白你使用的算法。
【解决方案2】:

是的,添加 close 是一个不错的举措。它应该有助于解决您的内存泄漏问题。我还建议将图形、绘图和关闭命令移到循环之外 - 只需更新 plot 创建的 Line2D 实例。查看this 了解更多信息。

注意:我认为这应该可以,但我没有在这里测试过。

【讨论】:

  • 这种方法是否会像clf() 那样保存过去的绘图日志?
  • 我想我的意思是你提到的内存泄漏。我之前只是略过一些东西,并认为我读到清除情节可以保存导致内存泄漏的情节的历史(或类似性质的东西),但我不太确定。
  • 啊,好的。看看this。本质上, clf() 不会删除对图形的内部引用,因此它不会消失 - 即,您创建 ~2K 图形并将它们保存在内存中。我建议的方式只是创建一个图形和一个 Line2D 对象。您可以随时更新线点。
  • 这是有道理的。所以我会减少每次制作一个新人物的时间。快速提问。由于溢出错误,我的程序刚刚崩溃。我想太多的数据点。在不改变绘制的数据点数量的情况下如何防止这种情况发生?
  • 其实开个玩笑。我想我知道如何解决这个问题。
【解决方案3】:

我测试了类似于您在 ipython 中所做的事情,我注意到当目录中有很多文件时循环变得相当慢。看起来该目录中的文件系统的开销与该文件夹中的文件数量有关,可能与以下各项的查找时间有关:

loadtxt(filename, unpack = true)

您可以尝试通过将文件列表拆分为较小的块并为每个块保存在不同的目录中来将保存地块的位置拆分为块。

【讨论】:

  • 是的,我想我一定会记住这一点以供将来参考,但现在我时间紧迫,所以我无法做出改变。 :(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-22
  • 1970-01-01
  • 2021-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-09
相关资源
最近更新 更多