在下面的代码中,我试图释放一个正在由运行
multiprocessing.connection.Listener
的 python 线程监听的网络端口。尝试失败并出现“地址已在使用中”错误。在线程中运行此类 Listener
、释放其资源并能够使用新的 Listener
侦听同一端口来启动新线程的可靠方法是什么?除了可靠之外,还有比重复检查我尝试使用的变量self.stopped
更优雅的方法吗?
import gc
import threading
import time
from multiprocessing.connection import Listener
class MyListener(threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self, daemon=False)
self.name = name
self.address = ('localhost', 5000)
self.stopped = False
self.print("Object constructed")
def run(self):
self.print("Thread started")
if self.stopped:
self.print("exit run 1")
return
with Listener(self.address) as listener:
self.print("Listener created")
self.listener = listener
if self.stopped:
self.close()
self.print("exit run 2")
return
while not self.stopped:
with listener.accept() as conn:
self.conn = conn
if self.stopped:
self.close()
self.print("exit run 3")
return
msg = self.conn.recv()
self.print("exit run 4")
self.close()
def close(self):
self.print("Closing")
self.stopped = True
try:
conn = self.conn
except:
conn = None
self.print("No connection to close")
if not conn is None:
self.print("Closing connection")
conn.close()
del self.conn
try:
listener = self.listener
except:
listener = None
self.print("No listener to close")
if not listener is None:
self.print("Listener closing")
self.listener.close()
del self.listener
self.print("Listener closed")
gc.collect()
self.print("All closed")
def print(self, text):
thread_name = threading.current_thread().name
if thread_name == "MainThread":
thread_name = "M"
print(thread_name +":" + self.name + ": " + text)
sleepseconds=1
l1 = MyListener(name="A")
time.sleep(sleepseconds)
l1.start()
time.sleep(sleepseconds)
l1.close()
time.sleep(sleepseconds)
l2 = MyListener(name="B")
time.sleep(sleepseconds)
l2.start()
time.sleep(sleepseconds)
l2.close()
我使用 python 3.12.4 的输出如下:
M:A: Object constructed
A:A: Thread started
A:A: Listener created
M:A: Closing
M:A: No connection to close
M:A: Listener closing
M:A: Listener closed
M:A: All closed
M:B: Object constructed
B:B: Thread started
Exception in thread B:
Traceback (most recent call last):
File "/usr/lib64/python3.12/threading.py", line 1073, in _bootstrap_inner
self.run()
File "/home/user/PlayListener.py", line 23, in run
with Listener(self.address) as listener:
^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.12/multiprocessing/connection.py", line 464, in __init__
self._listener = SocketListener(address, family, backlog)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.12/multiprocessing/connection.py", line 608, in __init__
self._socket.bind(address)
OSError: [Errno 98] Address already in use
M:B: Closing
M:B: No connection to close
M:B: No listener to close
M:B: All closed
此处给出了相关问题的答案。相应的,看起来靠谱的就是替换close方法如下:
def close(self):
self.stopped = True
try:
Client(self.address)
except ConnectionRefusedError:
pass
try:
conn = self.conn
except:
conn = None
if not conn is None:
conn.close()
try:
listener = self.listener
except:
listener = None
if not listener is None:
self.listener.close()
优雅仍有待发现。