我知道关于这个主题还有很多其他问题,我已经阅读/试验过这些解决方案,但是没有一个能完全符合我的要求或者没有工作......
我想做什么:
我想使用matplotlib创建一个绘图,在新进程中启动该绘图,使其在主线程运行时打开并响应,此外当主线程退出时不会杀死子进程。如果可能的话,我想要一些便携的东西因此我避免使用叉子,因为我的印象是它不是(正确吗?)。我在matplotlib中尝试过show(block = False)。如果没有其他任何事情我很乐意接受,但最好主要线程退出并且情节仍然坐在那里。
到目前为止我最好的尝试:
此代码已从Python close children when closing main process
修改import logging, signal, sys, time
import multiprocessing as mp
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid.axislines import SubplotZero
class AddProcessNameFilter(logging.Filter):
"""Add missing on Python 2.4 `record.processName` attribute."""
def filter(self, r):
r.processName = getattr(r, 'processName', mp.current_process().name)
return logging.Filter.filter(self, r)
def print_dot(plt):
signal.signal(signal.SIGTERM, signal.SIG_IGN)
while True:
mp.get_logger().info(".")
plt.show(block=True)
def main():
logger = mp.log_to_stderr()
logger.setLevel(logging.INFO)
logger.addFilter(AddProcessNameFilter()) # fix logging records
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot([0, 1, 2, 3], [1, 1, 3, 2],'ro')
# create daemonic child processes
p = mp.Process(target=print_dot, args=(plt,))
p.daemon = True
p.start()
if __name__=="__main__":
mp.freeze_support()
main()
此代码会发生什么......
剧情未启动另外主线程不退出它只是等待连接。中断时我也会收到以下错误......
X Error of failed request: BadIDChoice (invalid resource ID chosen for this connection)
Major opcode of failed request: 53 (X_CreatePixmap)
Resource id in failed request: 0x4400017
Serial number of failed request: 344
Current serial number in output stream: 352
不确定该怎么做。有任何想法吗? 提前致谢:D
PS:Ubuntu 12.04 ......但我不知道在这种情况下这是否特别相关...
答案 0 :(得分:0)
我使用以下代码。它类似于你的,但加入旧进程,因为该函数应该被多次调用。您可以关闭主要流程,但不会关闭该地块。
无法保证在调用p.start之后将显示该图。但这很不寻常,只发生在我身上几次。在这些时候,如果再次调用plot或者调用p.is_alive(),则会显示窗口。
import multiprocessing as mp
import sys
def foo(*arg):
import matplotlib.pyplot as plt
plt.ioff()
plt.plot(*arg)
plt.show()
if __name__ == '__main__':
mp.freeze_support()
arg=(range(10),)
global pl
#create the process list, if it does not exists
try:
pl
except NameError:
pl = []
#Join old ones to keep zombie process list small
for i in range(len(pl)):
if not (pl[i] is None):
if not pl[i].is_alive():
pl.pop(i).join()
#create plot process
p = mp.Process(target=foo, args=arg)
p.start()
pl.append(p)
答案 1 :(得分:0)
我推荐https://stackoverflow.com/a/62354049/13995577的解决方案。对我来说效果很好。虽然有点小,但相对较小。
import multiprocessing as mp
def my_plot_routine(q):
...
q.put('Done, see plot window')
plt.show()
return
class EverLastingProcess(mp.Process):
def join(self, *args, **kwargs):
pass
def __del__(self):
pass
if __name__ == '__main__':
# create plot process
mp.set_start_method('spawn')
q = mp.Queue()
p = EverLastingProcess(target=my_plot_routine, args=(q,))
p.start()
print(q.get())