如果这种性能很慢,您将不得不找到一些花哨的东西。它几乎都在 C 级运行:
for filename in filenames:
with open(filename, 'r+') as f:
data = f.read()
f.seek(0)
f.truncate()
for k, v in mappings.items():
data = data.replace(k, v)
f.write(data)
请注意,您可以运行多个进程,其中每个进程处理文件总列表的一部分。这应该使整个工作更快。没什么特别的,只需在 shell 中运行多个实例,每个实例都有不同的文件列表。
显然str.replace 比 regex.sub 快。
所以我要多考虑一下:假设你有一个非常大的mappings
. 如此之多,以至于mappings
在您的文件中检测到任何一个键的可能性非常低。在这种情况下,所有时间都将用于搜索(正如@abarnert 所指出的那样)。
在诉诸奇异算法之前,multiprocessing
至少可以用于并行搜索,然后在一个进程中进行替换(由于显而易见的原因,您不能在多个进程中进行替换:您将如何组合结果),这似乎是合理的?)。
所以我决定最终对 有一个基本的了解multiprocessing
,下面的代码看起来似乎可以正常工作:
import multiprocessing as mp
def split_seq(seq, num_pieces):
# Splits a list into pieces
start = 0
for i in xrange(num_pieces):
stop = start + len(seq[i::num_pieces])
yield seq[start:stop]
start = stop
def detect_active_keys(keys, data, queue):
# This function MUST be at the top-level, or
# it can't be pickled (multiprocessing using pickling)
queue.put([k for k in keys if k in data])
def mass_replace(data, mappings):
manager = mp.Manager()
queue = mp.Queue()
# Data will be SHARED (not duplicated for each process)
d = manager.list(data)
# Split the MAPPINGS KEYS up into multiple LISTS,
# same number as CPUs
key_batches = split_seq(mappings.keys(), mp.cpu_count())
# Start the key detections
processes = []
for i, keys in enumerate(key_batches):
p = mp.Process(target=detect_active_keys, args=(keys, d, queue))
# This is non-blocking
p.start()
processes.append(p)
# Consume the output from the queues
active_keys = []
for p in processes:
# We expect one result per process exactly
# (this is blocking)
active_keys.append(queue.get())
# Wait for the processes to finish
for p in processes:
# Note that you MUST only call join() after
# calling queue.get()
p.join()
# Same as original submission, now with MUCH fewer keys
for key in active_keys:
data = data.replace(k, mappings[key])
return data
if __name__ == '__main__':
# You MUST call the mass_replace function from
# here, due to how multiprocessing works
filenames = <...obtain filenames...>
mappings = <...obtain mappings...>
for filename in filenames:
with open(filename, 'r+') as f:
data = mass_replace(f.read(), mappings)
f.seek(0)
f.truncate()
f.write(data)
一些注意事项:
- 我还没有执行这段代码!我希望在某个时候对其进行测试,但是创建测试文件等需要时间。请认为它介于伪代码和有效 python 之间。让它运行应该不难。
- 可以想象,使用多台物理机器应该很容易,即具有相同代码的集群。
multiprocessing
用于展示如何使用网络上的机器的文档。
- 这段代码还是很简单的。我很想知道它是否能提高你的速度。
- 使用多处理似乎有很多骇人听闻的警告,我试图在评论中指出。由于我还不能测试代码,可能是我没有正确使用多处理。