如何解决在与Python不同的线程/进程中运行多个Python文件pyzmq套接字未正确关闭 运行脚本使用脚本第二次出错
项目结构
我具有以下文件结构(从真实项目中简化):
quickstart.py
module_pub
|- main.py
|- module specific files
module_sub
|- main.py
|- module specific files
客观
我希望Linux和Windows(可选:Mac)上的用户都可以使用以下命令同时运行所有模块:
conda activate project_env
python quickstart.py
但是,如果在运行此quickstart.py
时发出ctrl-c命令,它将无法正确关闭pyzmq套接字。第一次运行此脚本,它可以运行,但是第二次它抛出一个zmq.error.ZMQError: Address already in use
(在Ubuntu 18.04上)。
我想使用一个Python文件(quickstart.py
)启动其他模块,从而正确关闭ctrl-c上的套接字。
尽管我在这里使用的是pyzmq
的Python zeromq
,但我认为问题在于进程如何关闭。
有效代码
发布商
module_pub / main.py
import asyncio
import zmq.asyncio
from zmq.asyncio import Context
class MessagePublisher:
def __init__(self):
ctx = Context.instance()
self.socket = ctx.socket(zmq.PUB)
url = "tcp://0.0.0.0:5555"
self.socket.bind(url)
print(f"Pub bound to: {url}")
async def send_msg(self):
# (project case) use local files
i = 1
while True:
msg = str(i)
print(f"Sending msg: {msg}")
await self.socket.send(msg.encode('ascii'))
i += 1
await asyncio.sleep(1)
if __name__ == '__main__':
sender = MessagePublisher()
asyncio.get_event_loop().run_until_complete(asyncio.wait([sender.send_msg()]))
订户
module_sub / main.py
import asyncio
import zmq.asyncio
from zmq.asyncio import Context
class MessageSubscriber:
def __init__(self):
ctx = Context.instance()
self.socket = ctx.socket(zmq.SUB)
url = "tcp://0.0.0.0:5555"
self.socket.connect(url)
self.socket.setsockopt(zmq.SUBSCRIBE,''.encode('ascii')) # any topic
print(f"Sub connected to: {url}")
async def receive_msg(self):
# (project case) use local files
while True:
msg = await self.socket.recv()
print(f"Received msg: {msg.decode('ascii')}")
if __name__ == '__main__':
sender = MessageSubscriber()
asyncio.get_event_loop().run_until_complete(asyncio.wait([sender.receive_msg()]))
如何执行
端子1:
conda activate project_env
cd module_sub
python main.py
端子2:
conda activate project_env
cd module_pub
python main.py
成功!直到这里为止。
进行快速入门。
尝试1
import sys
import threading
import subprocess
from multiprocessing import Pool
def module_thread(folder):
print(f"Executing module: {folder}")
subprocess.run([sys.executable,"main.py"],cwd=folder) #,timeout=2
with Pool() as p:
print(p.map(module_thread,["module_sub","module_pub"]))
运行脚本
conda activate project_env
python quickstart.py # works
ctrl-c # interrupt script
python quickstart.py # Error: Address already in use
使用脚本第二次出错
python quickstart_zmq.py
Executing module: module_sub
Executing module: module_pub
Traceback (most recent call last):
File "main.py",line 26,in <module>
sender = MessagePublisher()
File "main.py",line 11,in __init__
self.socket.bind(url)
File "zmq/backend/cython/socket.pyx",line 550,in zmq.backend.cython.socket.socket.bind
File "zmq/backend/cython/checkrc.pxd",in zmq.backend.cython.checkrc._check_rc
zmq.error.ZMQError: Address already in use
Sub connected to: tcp://0.0.0.0:5555
其他尝试
我尝试了以下解决方案:python subprocess.call doesn't handle signal correctly 但是,结果是一样的,地址已被使用。
我也无法使其与线程一起工作,例如exec(open(f"{folder}/main.py").read())
。
恢复已在使用的地址
要释放套接字,我需要在Ubuntu 18.04上运行以下命令:sudo killall python
什么起作用
将,timeout=5
添加到subprocess.run([sys.executable,cwd=folder,timeout=5)
(尝试1)将在正确关闭套接字的同时结束脚本。不幸的是,在用户决定使用ctrl-c停止该模块之前,我需要这些模块保持运行。
系统
- Ubuntu 18.04(尚未测试Windows 10)
- Python:3.7.7
- pyzmq:19.0.1
- zeromq:4.3.2
必需的解决方案
- 启动其他Python脚本(例如模块)的单个Python脚本
- 由于相对导入(
cwd=folder
),路径上下文应设置在模块文件夹中 - 从
if __name__ == '__main__':
执行脚本 - 当用户使用ctrl-c时,正确关闭进程,以便释放套接字端口。这样可以使脚本多次执行。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。