我想知道如何正确创建后台线程,该后台线程会收听一些随机端口并将接收到的对象推送到队列?
我希望我的套接字包装器启动新线程,选择一些随机端口并开始监听。我必须能够从套接字包装器中获取此端口号。
我想出了简单的课程:
class SocketWrapper(Thread):
def __init__(self, socket_type, *args, **kwargs):
super(Thread, self).__init__(*args, **kwargs)
self._ctx = zmq.Context()
self._socket = self._ctx._socket(socket_type)
self.port = self._socket.bind_to_random_port('tcp://*')
self._queue = Queue()
def run(self):
while not self.stop_requested:
try:
item = socket.recv_pyobj(flags=zmq.NOBLOCK)
self._queue.put(item)
except ZMQError:
time.sleep(0.01) # Wait a little for next item to arrive
但是,zmq套接字不能在线程之间共享,它们不是线程安全的(http://api.zeromq.org/2-1:zmq)。因此,套接字创建和绑定应移至run()
方法:
class SocketWrapper2(Thread):
def __init__(self, socket_type, *args, **kwargs):
super(Thread, self).__init__(*args, **kwargs)
self._socket_type = socket_type
self._ctx = zmq.Context()
self._queue = Queue()
self._event = Event()
def run(self):
socket = self._ctx._socket(self._socket_type)
self.port = self._socket.bind_to_random_port('tcp://*')
self._event.set()
while not self.stop_requested:
try:
item = socket.recv_pyobj(flags=zmq.NOBLOCK)
self._queue.put(item)
except ZMQError:
time.sleep(0.01) # Wait a little for next item to arrive
def get_port(self):
self._event.wait()
return self.port
我必须添加事件以确保端口已经绑定,然后才能读取它,但是当在start()之前调用SocketWrapper2.get_port()时,它会引入死锁的风险。使用Thread的_started Event:
可以避免这种情况 def get_port(self):
if not self._started.is_set():
raise RuntimeError("You can't call run_port before thread start.")
self._event.wait()
return self.port
这是最后的线程安全吗?还有什么需要照顾的吗?
我仍然在这里看到的问题是我想在创建SocketWrapper后立即获得端口。我可以安全地在start()
中调用线程__init__
吗?
答案 0 :(得分:0)
我最后修改了这个解决方案以避免死锁主线程:
def get_port(self):
if not self._started.is_set():
raise RuntimeError("You can't call run_port before thread start.")
if not self._event.wait(1):
raise RuntimeError("Couldn't get port after a while.")
return self.port
这并不完美。因为我们延迟了get_port,但它很简单并完成了工作。有任何建议如何改进吗?