场景 - 我有一个我正在执行任务的进程池。但是,如果在运行任务时终止了子进程,则AsyncResult
对象永远不会被标记为就绪。我希望会发生的事情是它会被标记为准备好并且不成功。
重现这一点:
>>> import multiprocessing
>>> import time
>>> p = multiprocessing.Pool(processes=1)
>>> result = p.apply_async(time.sleep, args=(1000,))
>>> result.ready()
False
在另一个shell中,找到进程ID并将其终止。
>>> result.ready()
False
>>> result.wait(5) # Waits 5 seconds even though subprocess is dead
这是一个问题,因为我有一个线程在等待作业完成,并且通常有一个相当长的超时。如何在不需要等待超时的情况下完成result.wait(timeout)
调用?另外,我怎么知道它已被放弃,而不仅仅是任务仍在运行但是我们达到了超时?
答案 0 :(得分:1)
如果进程意外死亡,Pebble库会通知您。它还支持超时和回调。
这是你的榜样。
from pebble import ProcessPool
from concurrent.futures import TimeoutError
with ProcessPool() as pool:
future = pool.schedule(time.sleep, args=(1000,), timeout=100)
try:
results = future.result()
print(results)
except TimeoutError as error:
print("Function took longer than %d seconds" % error.args[1])
except ProcessExpired as error:
print("%s. Exit code: %d" % (error, error.exitcode))
except Exception as error:
print("function raised %s" % error)
print(error.traceback) # Python's traceback of remote process
documentation中的更多示例。
答案 1 :(得分:1)
呼叫result.wait()
将一直等到timeout
,除非它从池中收到信号。但是,如果执行kill -9 [pid]
,则池将立即启动队列中的下一个作业。
因此,它更容易使用,然后手动"民意调查"并检查ready()
。您所说的问题是,当作业被杀时,ready()
仍为False
。
要解决此问题,您可以检查pid是否存活。由于ApplyResult
没有携带pid,因此您需要其他方法来获取它。你可以这样做:
def test(identifier):
pid = os.getpid()
f = open("pids/" + str(pid), "w")
f.write(str(identifier))
f.close()
# do stuff
time.sleep(1000)
然后创建这样的工作(考虑jobs = []
)。
job = (identifier, pool.apply_async(test, (identifier,)))
jobs.append(job)
标识符不是必需的,但如果您稍后想要确定哪个ApplyResult
属于哪个pid,则非常有用。
然后,您可以获得所有工作,并检查每个工作(pid)是否还活着:
def is_alive(pid):
return os.path.exists("/proc/" + str(pid))
for pid in os.listdir("pids"):
if is_alive(pid):
...
else:
...
考虑每个pid命名文件的内容。然后使用identifier
中的jobs
,您现在可以链接哪个ApplyResult
属于哪个pid,并专门检查哪个作业已死或ready()
或者如果以上都不是然后还在跑步。
您还可以创建一个管道并分叉一个子进程。
r, w = os.pipe()
def child():
global r, w
data = ...
time.sleep(100)
os.close(r)
w = os.fdopen(w, "w")
w.write(data)
w.close()
然后,您只需将数据写回父进程。
def parent(child_pid):
global r, w
os.close(w)
r = os.fdopen(r)
data = r.read()
r.close()
status = os.waitpid(child_pid, 0)
if status == 0:
# Everything is fine
elif status == 9:
# kill -9 [pid]
# Process data
然后,您可以使用收到的status
和data
来确定子进程发生了什么。
你可以通过这样做来开始。
if __name__ == "__main__":
child_pid = os.fork()
if child_pid:
parent(child_pid)
else:
child()
从你的问题我假设是Unix。如果没有随意纠正我。如果任何非Python 2.7潜入答案,那么我道歉。