Skip to content

Commit 0c4ec88

Browse files
committed
azy-init shared context instead of one per port
1 parent 7736a97 commit 0c4ec88

1 file changed

Lines changed: 25 additions & 10 deletions

File tree

concore_base.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,28 @@
1111
# ===================================================================
1212
# ZeroMQ Communication Wrapper
1313
# ===================================================================
14-
# single shared ZMQ context for the entire process.
15-
_zmq_context = zmq.Context()
14+
# lazy-initialized shared ZMQ context for the entire process.
15+
# using None until first ZMQ port is created, so file-only workflows
16+
# never spawn ZMQ I/O threads at import time.
17+
_zmq_context = None
18+
19+
def _get_zmq_context():
20+
"""Return the process-level shared ZMQ context, creating it on first call."""
21+
global _zmq_context
22+
if _zmq_context is None or _zmq_context.closed:
23+
_zmq_context = zmq.Context()
24+
return _zmq_context
1625

1726
class ZeroMQPort:
18-
def __init__(self, port_type, address, zmq_socket_type, context):
27+
def __init__(self, port_type, address, zmq_socket_type, context=None):
1928
"""
2029
port_type: "bind" or "connect"
2130
address: ZeroMQ address (e.g., "tcp://*:5555")
2231
zmq_socket_type: zmq.REQ, zmq.REP, zmq.PUB, zmq.SUB etc.
23-
context: shared zmq.Context() for the process
32+
context: optional zmq.Context() for the process; defaults to the shared _zmq_context.
2433
"""
34+
if context is None:
35+
context = _get_zmq_context()
2536
self.socket = context.socket(zmq_socket_type)
2637
self.port_type = port_type # "bind" or "connect"
2738
self.address = address
@@ -79,7 +90,7 @@ def init_zmq_port(mod, port_name, port_type, address, socket_type_str):
7990
try:
8091
# Map socket type string to actual ZMQ constant (e.g., zmq.REQ, zmq.REP)
8192
zmq_socket_type = getattr(zmq, socket_type_str.upper())
82-
mod.zmq_ports[port_name] = ZeroMQPort(port_type, address, zmq_socket_type, _zmq_context)
93+
mod.zmq_ports[port_name] = ZeroMQPort(port_type, address, zmq_socket_type, _get_zmq_context())
8394
logger.info(f"Initialized ZMQ port: {port_name} ({socket_type_str}) on {address}")
8495
except AttributeError:
8596
logger.error(f"Error: Invalid ZMQ socket type string '{socket_type_str}'.")
@@ -108,11 +119,15 @@ def terminate_zmq(mod):
108119
logger.error(f"Error while terminating ZMQ port {port.address}: {e}")
109120
mod.zmq_ports.clear()
110121

111-
# terminate the single shared context exactly once.
112-
try:
113-
_zmq_context.term()
114-
except Exception as e:
115-
logger.error(f"Error while terminating shared ZMQ context: {e}")
122+
# terminate the single shared context exactly once, then reset so it
123+
# can be safely recreated if init_zmq_port is called again later.
124+
global _zmq_context
125+
if _zmq_context is not None and not _zmq_context.closed:
126+
try:
127+
_zmq_context.term()
128+
except Exception as e:
129+
logger.error(f"Error while terminating shared ZMQ context: {e}")
130+
_zmq_context = None
116131

117132
mod._cleanup_in_progress = False
118133

0 commit comments

Comments
 (0)