<p>我认为,与其使用<code>threading</code>模块,不如将<code>multiprocessing</code>模块用于Python解决方案。Python线程可能会与GIL相冲突;如果只需要多个Python进程,GIL就不是问题。在</p>
<p>我认为对于你正在做的事情,一个工人进程池正是你想要的。默认情况下,对于系统处理器中的每个内核,池将默认为一个进程。只需使用要检查的文件名列表和执行检查的函数调用<code>.map()</code>方法。在</p>
<p><a href="http://docs.python.org/library/multiprocessing.html" rel="nofollow">http://docs.python.org/library/multiprocessing.html</a></p>
<p>如果这不比您的<code>threading</code>实现快,那么我不认为GIL是您的问题。在</p>
<p>编辑:好的,我正在添加一个正在工作的Python程序。这使用一个工作进程池来打开每个文件并在每个文件中搜索模式。当worker找到匹配的文件名时,它只需将其打印(到标准输出),这样您就可以将此脚本的输出重定向到一个文件中,您就可以得到文件列表了。在</p>
<p>编辑:我认为这是一个稍微容易阅读的版本,更容易理解。在</p>
<p>我在电脑上搜索/usr/include中的文件,以此来计时。它在半秒钟内完成搜索。使用<code>find</code>管道通过<code>xargs</code>来运行尽可能少的<code>grep</code>进程,大约需要0.05秒,大约10倍的加速。但是我讨厌你必须使用巴洛克风格的怪异语言来使<code>find</code>正常工作,我喜欢Python版本。也许在真正大的目录上,差距会更小,因为Python的半秒时间一定是启动时间。也许半秒钟对大多数目的来说已经足够快了!在</p>
<pre><code>import multiprocessing as mp
import os
import re
import sys
from stat import S_ISREG
# uncomment these if you really want a hard-coded $HOME/patterns file
#home = os.environ.get('HOME')
#patterns_file = os.path.join(home, 'patterns')
target = sys.argv[1]
size_limit = int(sys.argv[2])
assert size_limit >= 0
patterns_file = sys.argv[3]
# build s_pat as string like: (?:foo|bar|baz)
# This will match any of the sub-patterns foo, bar, or baz
# but the '?:' means Python won't bother to build a "match group".
with open(patterns_file) as f:
s_pat = r'(?:{})'.format('|'.join(line.strip() for line in f))
# pre-compile pattern for speed
pat = re.compile(s_pat)
def walk_files(topdir):
"""yield up full pathname for each file in tree under topdir"""
for dirpath, dirnames, filenames in os.walk(topdir):
for fname in filenames:
pathname = os.path.join(dirpath, fname)
yield pathname
def files_to_search(topdir):
"""yield up full pathname for only files we want to search"""
for fname in walk_files(topdir):
try:
# if it is a regular file and big enough, we want to search it
sr = os.stat(fname)
if S_ISREG(sr.st_mode) and sr.st_size >= size_limit:
yield fname
except OSError:
pass
def worker_search_fn(fname):
with open(fname, 'rt') as f:
# read one line at a time from file
for line in f:
if re.search(pat, line):
# found a match! print filename to stdout
print(fname)
# stop reading file; just return
return
mp.Pool().map(worker_search_fn, files_to_search(target))
</code></pre>