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
其中string
是foo
。
【讨论】:
谢谢你的回答,你说怎么修改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() 缓存/加速的主要内容,如果未能解决你的问题,请参考以下文章