在Python中是否可以在线程内生成进程?
我正在编写一个生成进程并在特定条件下重新启动进程的程序。例如,如果子进程不再向母进程发送数据,在一段时间内,我希望母进程终止子进程并重新启动它。我原以为可以使用线程从子进程接收数据并重新启动子进程,但它没有按照我的想法工作在Python中是否可以在线程内生成进程?,python,windows,multithreading,multiprocessing,python-multiprocessing,Python,Windows,Multithreading,Multiprocessing,Python Multiprocessing,我正在编写一个生成进程并在特定条件下重新启动进程的程序。例如,如果子进程不再向母进程发送数据,在一段时间内,我希望母进程终止子进程并重新启动它。我原以为可以使用线程从子进程接收数据并重新启动子进程,但它没有按照我的想法工作 import numpy as np import multiprocessing as mp import threading import time from apscheduler.schedulers.background import BackgroundSched
import numpy as np
import multiprocessing as mp
import threading
import time
from apscheduler.schedulers.background import BackgroundScheduler
pipe_in, pipe_out = mp.Pipe()
class Mother():
def __init__(self):
self.pipe_out = pipe_out
self.proc = mp.Process(target = self.test_func, args=(pipe_in, ))
self.proc.start()
self.thread = threading.Thread(target=self.thread_reciever, args=(self.pipe_out, ))
self.thread.start()
def thread_reciever(self, pipe_out):
while True:
value = pipe_out.recv()
print(value)
if value == 5:
self.proc.terminate()
time.sleep(2)
self.proc = mp.Process(target = self.test_func)
self.proc.start()
def test_func(self, pipe_in):
for i in range(10):
pipe_in.send(i)
time.sleep(1)
if __name__ == '__main__':
r = Mother()
它会打印出这个错误
D:\>d:\python36-32\python.exe temp06.py
0
1
2
3
4
5
Exception in thread Thread-1:
Traceback (most recent call last):
File "d:\python36-32\lib\threading.py", line 916, in _bootstrap_inner
self.run()
File "d:\python36-32\lib\threading.py", line 864, in run
self._target(*self._args, **self._kwargs)
File "temp06.py", line 28, in thread_reciever
self.proc.start()
File "d:\python36-32\lib\multiprocessing\process.py", line 105, in start
self._popen = self._Popen(self)
File "d:\python36-32\lib\multiprocessing\context.py", line 223, in _Popen
return _default_context.get_context().Process._Popen(process_obj)
File "d:\python36-32\lib\multiprocessing\context.py", line 322, in _Popen
return Popen(process_obj)
File "d:\python36-32\lib\multiprocessing\popen_spawn_win32.py", line 65, in __init__
reduction.dump(process_obj, to_child)
File "d:\python36-32\lib\multiprocessing\reduction.py", line 60, in dump
ForkingPickler(file, protocol).dump(obj)
TypeError: can't pickle _thread.lock objects
D:\>Traceback (most recent call last):
File "<string>", line 1, in <module>
File "d:\python36-32\lib\multiprocessing\spawn.py", line 99, in spawn_main
new_handle = reduction.steal_handle(parent_pid, pipe_handle)
File "d:\python36-32\lib\multiprocessing\reduction.py", line 82, in steal_handle
_winapi.PROCESS_DUP_HANDLE, False, source_pid)
OSError: [WinError 87]
输出
D:\> d:\python36-32\python.exe temp06.py
0
1
2
3
4
5
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "d:\python36-32\lib\multiprocessing\spawn.py", line 105, in spawn_main
exitcode = _main(fd)
File "d:\python36-32\lib\multiprocessing\spawn.py", line 115, in _main
self = reduction.pickle.load(from_parent)
AttributeError: Can't get attribute 'test_func' on <module '__main__' (built-in)>
在windows下,由于没有fork系统调用,python启动一个新的解释器实例,使用pickle/unpickle重构执行上下文,但thread.Lock不可拾取。在pickle self.test_func时,对thread.Lock对象的self.thread引用使其不可pickle 您可以简单地将test_func更改为普通全局函数,而无需线程对象引用:
self.proc = mp.Process(target = test_func, args=(pipe_in,))
...
def test_func(pipe_in):
for i in range(10):
pipe_in.send(i)
time.sleep(1)
在windows下,由于没有fork系统调用,python启动一个新的解释器实例,使用pickle/unpickle重构执行上下文,但thread.Lock不可拾取。在pickle self.test_func时,对thread.Lock对象的self.thread引用使其不可pickle 您可以简单地将test_func更改为普通全局函数,而无需线程对象引用:
self.proc = mp.Process(target = test_func, args=(pipe_in,))
...
def test_func(pipe_in):
for i in range(10):
pipe_in.send(i)
time.sleep(1)
我认为当self.test_func是目标时,必须对整个self对象进行pickle。但是在第二个进程创建时,self.thread中有一个线程对象不能被pickle。尝试将thread对象存储在类之外。我认为当self.test_func作为目标时,必须对整个self对象进行pickle。但是在第二个进程创建时,self.thread中有一个线程对象不能被pickle。尝试将线程对象存储在类之外。谢谢您的回答。实际上,我的目标是让程序终止,并根据从它自己的子进程接收到的数据,每5秒执行一个新进程。这就是我用线的原因。有什么方法可以做到这一点吗?我只是按照你的建议将test_func更改为全局函数,错误为AttributeError:无法获取属性“test_func”。这是否意味着在主名称空间中找不到test_func?我已将更改后的代码添加到问题中。谢谢你帮助我@maynull快速而肮脏的解决方法:将test_func移动到另一个模块,然后导入到当前脚本。从其他文件导入函数时,该方法可以正常工作。谢谢你的提示。我想知道这是否是Python的问题。谢谢你的回答。实际上,我的目标是让程序终止,并根据从它自己的子进程接收到的数据,每5秒执行一个新进程。这就是我用线的原因。有什么方法可以做到这一点吗?我只是按照你的建议将test_func更改为全局函数,错误为AttributeError:无法获取属性“test_func”。这是否意味着在主名称空间中找不到test_func?我已将更改后的代码添加到问题中。谢谢你帮助我@maynull快速而肮脏的解决方法:将test_func移动到另一个模块,然后导入到当前脚本。从其他文件导入函数时,该方法可以正常工作。谢谢你的提示。我不知道这是否是Python的问题。