- 我有一个 300m 行的文件 (inputFile),所有文件都有 2 列,用制表符分隔。
- 我还有一个包含 1000 个唯一项 (vals) 的列表。
我想为 inputFile 中的所有行创建一个字典,其中第 1 列作为键,第 2 列作为值,其中第一列出现在 vals 中。 vals 中的一些项目没有出现在文件中,这些值必须保存在新列表中。我最多可以使用 20 个线程来加速这个过程。
实现此目标的最快方法是什么?
到目前为止我的最佳尝试:
newDict = {}
foundVals = []
cmd = "grep \"" + vals[0]
for val in vals:
cmd = cmd + "\|^"+val+"[[:space:]]"
cmd = cmd + "\" " + self.inputFile
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in iter(p.stdout.readline, ''):
info = line.split()
foundVals.append(info[0])
newDict.update({info[0]:info[1]})
p.wait()
notFound = [x for x in vals if x not in set(foundVals)]
例子 输入文件:
2 9913
3 9913
4 9646
...
594592886 32630
594592888 32630
594592890 32630
值:
[1,2,594592888]
想要的字典:
{2:9913,594592888:32630}
在 notFound 中:
[1]
最佳答案
您在评论中阐明每个键在数据中最多出现一次。从这一点以及只有 1000 个键的事实可以看出,在 Python 中完成的工作量是微不足道的;您几乎所有的时间都花在了等待 grep
的输出上。哪个好;您将线路提取委托(delegate)给专门的实用程序的策略仍然有效。但这意味着必须在行提取方面找到性能提升。
您可以通过优化您的正则表达式来加快速度。例如,而不是
^266[[:space:]]\|^801[[:space:]]\|^810[[:space:]]
你可以使用:
^\(266\|801\|810\)[[:space:]]
这样就不必为每个备选方案单独匹配 anchor 。我发现通过该更改,测试数据(1000 万行,25 个键)提高了大约 15%。
进一步的优化是统一交替中的公共(public)前缀:266\|801\|810
可以替换为等效的 266\|8\(01\|10\)
。以这种方式重写 25 键正则表达式可使测试数据加速接近 50%。
此时 grep
开始显示其局限性。它似乎受 CPU 限制:iostat
表明,在 grep 运行时,正则表达式的每一次连续改进都会增加每秒 IO 请求的数量。并且使用预热页面缓存和 --mmap
选项重新运行 grep
不会加快速度(如果文件 IO 是瓶颈,它可能会加快速度)。因此,更快的速度可能需要具有更快的正则表达式引擎的实用程序。
其中一个是 ag
(来源 here ),其正则表达式实现也执行自动优化,因此您无需进行太多手动调整。虽然我无法让 grep
在我的机器上在不到 ~12 秒的时间内处理测试数据,但 ag
对所有正则表达式变体在 ~0.5 秒内完成如上所述。
关于python - 在 python 中从文件中获取多个值的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22480514/