os.walk() 缓存/加速

Posted

技术标签:

【中文标题】os.walk() 缓存/加速【英文标题】:os.walk() caching/speeding up 【发布时间】:2010-08-21 10:34:30 【问题描述】:

我有一个原型服务器[0],它为客户端[0] 进行的每个查询执行os.walk()[1]。

我目前正在研究以下方法:

在内存中缓存这些数据, 加快查询速度,并 希望以后能够扩展到存储元数据和数据持久性。

我发现 SQL complicated 用于树结构,所以我想在实际使用 SQLite 之前我会得到一些建议

是否有任何可以处理此类数据的跨平台、可嵌入或可捆绑的非 SQL 数据库?

我的列表很小(10k-100k 个文件)。 我的连接数非常少(可能是 10-20)。 我还希望能够扩展以处理元数据。

[0] 服务器和客户端实际上是同一个软件,这是一个 P2P 应用程序,旨在在没有主服务器的情况下通过本地可信网络共享文件,使用zeroconf 进行发现,并扭曲用于几乎所有其他东西

[1] 查询时间为 1.2 秒,os.walk() 在 10,000 个文件上

这是我的 Python 代码中执行行走的相关函数:

def populate(self, string):
    for name, sharedir in self.sharedirs.items():
        for root, dirs, files, in os.walk(sharedir):
            for dir in dirs:
                if fnmatch.fnmatch(dir, string):
                    yield os.path.join(name, *os.path.join(root, dir)[len(sharedir):].split("/"))
            for file in files:
                if fnmatch.fnmatch(file, string): 
                    yield os.path.join(name, *os.path.join(root, ile)[len(sharedir):].split("/"))

【问题讨论】:

如果你不知道的话:有一个 libfam for python 的实现,允许你缓存结构而不会有过时的风险 这个*** question 似乎正在寻找类似的东西。答案可能有些用处。 @S.Lott:我在该链接中提供了一个配置文件,正如您所见,posix.stat 是程序的慢速部分,它是 os.walk 的一部分 如果我想匹配文件夹名称,我也必须将其与文件夹名称匹配,除非您有更好的主意? (我不想匹配文件的目录,因为这将返回整个子树我只想要它自己的文件夹)至于“原型”也许我应该使用“概念证明”这个词 我说过匹配 name 这是文件和文件夹共有的少数东西之一,目前使用 only 的名称我的搜索正如我所说的元数据即将推出 【参考方案1】:

你不需要持久化一个树形结构——事实上,你的代码正忙着目录树的自然树形结构成线性序列,那你为什么要重启下次从树上?

看起来你需要的只是一个有序的序列:

i   X    result of os.path.join for X

其中X,一个字符串,命名一个文件或目录(你对待它们只是一样的),i是一个递增的整数(以保持顺序),结果列,也是一个字符串,是结果os.path.join(name, *os.path.join(root, &c.

当然,这很容易放入 SQL 表中!

要第一次创建表,只需从填充函数中删除守卫if fnmatch.fnmatch(和string 参数),在 os.path.join 结果之前生成目录或文件,然后使用@987654325 @ 保存调用的enumerate(或者,使用自增列,您的选择)。要使用该表,populate 本质上变为:

select result from thetable where X LIKE '%foo%' order by i

其中stringfoo

【讨论】:

谢谢你的回答,你说怎么修改a目录?所以所有的孩子都被修改为? @Daniel,对不起,这个突然出现的新问题似乎与你原来的问题无关——我不明白你的意思(而且 cmets 几乎没有空间澄清—— - 没有代码等)。为什么不关闭我回答的这个问题并为您的新问题打开另一个问题? “一个问题一个问题”对我来说似乎是一个明智而理智的政策。 对不起,也许我需要澄清一下,您提供了一个数据结构和一种将数据添加到结构中的方法。但我看到更新数据的问题,特别是当目录被重命名或移动时,您必须遍历整个结构并在第 3 列上匹配(使用 LIKE)该目录中的每个文件,然后与第一个示例相比更新它在我提供的链接中,只需要更改一个节点。我只是想要你对这个问题的看法? @Daniel,如果前缀/a/b/c/重命名为/a/b/d/UPDATE thetable SET X='/a/b/d/'||SUBSTR(X,8)' WHERE X LIKE '/a/b/c/%'是通用的SQL解决方案。如果您知道没有同音词字典或子树,SET X=REPLACE(X,'/a/b/c/','/a/b/d/') 甚至只是 SET X=REPLACE(X,'/c/','/d/') 可能就足够了,这取决于您可能排除的同音词(如果有的话)。【参考方案2】:

一开始我误解了这个问题,但我认为我现在有一个解决方案(并且与我的其他答案完全不同,需要一个新的答案)。基本上,您第一次在目录上运行 walk 时执行正常查询,但您存储产生的值。第二次,您只需生成那些存储的值。我已经封装了 os.walk() 调用,因为它很短,但是您可以轻松地将生成器封装为一个整体。

cache = 
def os_walk_cache( dir ):
   if dir in cache:
      for x in cache[ dir ]:
         yield x
   else:
      cache[ dir ]    = []
      for x in os.walk( dir ):
         cache[ dir ].append( x )
         yield x
   raise StopIteration()

我不确定您的内存要求,但您可能需要考虑定期清理 cache

【讨论】:

好吧,用例只有 1-10 个非常大的目录,但不确定目录树是否真的会占用大量内存,这就是我考虑使用数据库引擎的原因,因为它会处理在我需要时优化内存和持久性【参考方案3】:

你看过MongoDB吗? mod_python 呢? mod_python 应该允许您执行 os.walk() 并将数据存储在 Python 数据结构中,因为脚本在连接之间是持久的。

【讨论】:

MongoDB 很容易捆绑吗?抱歉,我不确定您为什么建议使用 mod_python?不是仅限于 HTTP 吗?

以上是关于os.walk() 缓存/加速的主要内容,如果未能解决你的问题,请参考以下文章

python中的os.walk

os.walk详解

Python os.walk() 方法遍历文件目录

Python 之 os.walk()

os.walk简介

os.walk()