Python在另一个函数返回结果后结束函数
我可能完全错了,但这仍然是我所处的位置。我正在尝试搜索非常大的日志文件,在某些情况下可达30gb。我正在编写一个脚本来获取信息,并一直在使用多进程来加快速度。现在我正在测试同时运行两个函数,从顶部和底部搜索结果,这似乎是可行的。我想知道是否有可能停止一个函数,一个是另一个函数的结果。例如,如果top函数找到一个结果,它们都会停止。这样我就可以根据需要构建它Python在另一个函数返回结果后结束函数,python,Python,我可能完全错了,但这仍然是我所处的位置。我正在尝试搜索非常大的日志文件,在某些情况下可达30gb。我正在编写一个脚本来获取信息,并一直在使用多进程来加快速度。现在我正在测试同时运行两个函数,从顶部和底部搜索结果,这似乎是可行的。我想知道是否有可能停止一个函数,一个是另一个函数的结果。例如,如果top函数找到一个结果,它们都会停止。这样我就可以根据需要构建它 from file_read_backwards import FileReadBackwards from multiprocessing
from file_read_backwards import FileReadBackwards
from multiprocessing import Process
import sys
z = "log.log"
#!/usr/bin/env python
rocket = 0
def top():
target = "test"
with open(z) as src:
found= None
for line in src:
if len(line) == 0: break #happens at end of file, then stop loop
if target in line:
found= line
break
print(found)
def bottom():
target = "text"
with FileReadBackwards(z) as src:
found= None
for line in src:
if len(line) == 0: break #happens at end of file, then stop loop
if target in line:
found= line
break
print(found)
if __name__=='__main__':
p1 = Process(target = top)
p1.start()
p2 = Process(target = bottom)
p2.start()
以下是我在评论中提到的方法的概念证明:
import os
import random
import sys
from multiprocessing import Process, Value
def search(proc_no, file_name, seek_to, max_size, find, flag):
stop_at = seek_to + max_size
with open(file_name) as f:
if seek_to:
f.seek(seek_to - 1)
prev_char = f.read(1)
if prev_char != '\n':
# Landed in the middle of a line. Skip back one (or
# maybe more) lines so this line isn't excluded. Start
# by seeking back 256 bytes, then 512 if necessary, etc.
exponent = 8
pos = seek_to
while pos >= seek_to:
pos = f.seek(max(0, pos - (2 ** exponent)))
f.readline()
pos = f.tell()
exponent += 1
while True:
if flag.value:
break
line = f.readline()
if not line:
break # EOF
data = line.strip()
if data == find:
flag.value = proc_no
print(data)
break
if f.tell() > stop_at:
break
if __name__ == '__main__':
# list.txt contains lines with the numbers 1 to 1000001
file_name = 'list.txt'
info = os.stat(file_name)
file_size = info.st_size
if len(sys.argv) == 1:
# Pick a random value from list.txt
num_lines = 1000001
choices = list(range(1, num_lines + 1))
choices.append('XXX')
find = str(random.choice(choices))
else:
find = sys.argv[1]
num_procs = 4
chunk_size, remainder = divmod(file_size, num_procs)
max_size = chunk_size + remainder
flag = Value('i', 0)
procs = []
print(f'Using {num_procs} processes to look for {find} in {file_name}')
for i in range(num_procs):
seek_to = i * chunk_size
proc = Process(target=search, args=(i + 1, file_name, seek_to, max_size, find, flag))
procs.append(proc)
for proc in procs:
proc.start()
for proc in procs:
proc.join()
if flag.value:
print(find, 'found by proc', flag.value)
else:
print(find, 'not found')
在阅读了关于使用多处理和多线程读取文件的各种文章[1]之后,由于潜在的磁盘抖动和序列化读取,这两种方法似乎都不是很好的方法。因此,这里有一种不同的、更简单的方法,它的速度要快得多(至少对于我尝试使用的有一百万行的文件): 我很好奇30GB日志文件的性能如何
[1] 包括使用
多处理.Pool
和回调函数的简单示例。
在返回结果后终止剩余的池进程
使用这种方法,可以添加任意数量的进程,从文件中的不同偏移量进行搜索
import math
import time
from multiprocessing import Pool
from random import random
def search(pid, wait):
"""Sleep for wait seconds, return PID
"""
time.sleep(wait)
return pid
def done(result):
"""Do something with result and stop other processes
"""
print("Process: %d done." % result)
pool.terminate()
print("Terminate Pool")
pool = Pool(2)
pool.apply_async(search, (1, math.ceil(random() * 3)), callback=done)
pool.apply_async(search, (2, math.ceil(random() * 3)), callback=done)
# do other stuff ...
# Wait for result
pool.close()
pool.join() # block our main thread
这基本上与Blurp的答案相同,但我将其缩短了一点,使其更具一般性。正如你们所看到的,顶部应该是一个无限循环,但底部会立即停止顶部
from multiprocessing import Process
valNotFound = True
def top():
i=0
while ValNotFound:
i += 1
def bottom():
ValNotFound = False
p1 = Process(target = top)
p2 = Process(target = bottom)
p1.start()
p2.start()
您必须将共享标志传递给这两个进程。当一个人发现结果时,他就会设定它;另一个看到它已被设置并退出。另外,我想看看这个
FileReadBackwards
。看起来更像是要将文件分割成块,并向前读取每个块。没有实际的分割。您可以使用与top()
相同的逻辑查找到文件的中点,然后从那里开始。您不必逐字拆分它。您只需找到正确的偏移量,然后查找它,将偏移量传递给两个进程。关于限制,grep或ag是否受到限制?您阅读的是哪种存储?我做这件事的时间相当长——在大块文本上进行文本处理,通常使用Python,而您所描述的内容在性能差异方面与我的经验完全不符。我经常读SSD。嗯,我做错了什么。keep getting ValueError:没有足够的值来解包(预期为2,得到0),通过删除文件名、搜索字符串=sys.argv[1:]使其正常工作。第一次测试非常棒。超快!
from multiprocessing import Process
valNotFound = True
def top():
i=0
while ValNotFound:
i += 1
def bottom():
ValNotFound = False
p1 = Process(target = top)
p2 = Process(target = bottom)
p1.start()
p2.start()