Does NetworkX intend to add timeout arguments to its graph algorithms?
0 reputation · 19 Jul 2023, 05:15 UTC
0 reputation · 19 Jul 2023, 05:15 UTC
NetworkX’s core graph algorithms such as shortest_path and dijkstra_path currently run synchronously and do not accept timeout or cancellation arguments. Users who need a time limit must rely on external mechanisms like concurrent.futures or Unix signals, which introduce portability concerns and risk leaving internal structures in an inconsistent state. The project has an open discussion about adding optional timeout parameters, but no agreement exists on the API shape, implementation strategy, or potential performance impact.
Given these uncertainties, what factors should guide the decision to expose timeout support directly in NetworkX functions? Which design options balance usability, thread‑safety, and backward compatibility? How might a timeout feature be implemented without requiring users to wrap every algorithm call in a separate thread or process?
32275 reputation · 19 Jul 2023, 08:49 UTC
As of the information available here, NetworkX has no committed plan to add timeout parameters to algorithms like shortest_path or dijkstra_path. The discussion exists but has no agreed API shape, so any claim about intent should be treated as unconfirmed until the issue tracker or release notes show a merged decision. This is version-sensitive: check the current changelog and help(nx.shortest_path) in your installed version before assuming anything.
NetworkX algorithms are pure Python and run synchronously. CPython's GIL switches between bytecodes, but there is no supported way to interrupt a running loop from another thread — concurrent.futures timeouts only abandon the result, while the worker thread keeps consuming CPU. Unix signals (signal.alarm) work only on the main thread and can fire at arbitrary bytecode points, which is why they are discouraged as a library mechanism.
The saving grace is that most NetworkX algorithms do not mutate the input graph, so interruption does not corrupt graph state — the "inconsistent internal state" risk applies to the algorithm's local data, which is simply discarded.
None preserves every existing signature. A global/config-level timeout risks surprising behavior in libraries that call NetworkX internally.time.monotonic() check in a tight loop over millions of edges is not free; amortizing by checking every N iterations keeps overhead negligible.The design that balances usability, thread-safety, and compatibility is a cooperative token or deadline checked inside the algorithm loop, raising a documented exception (e.g., TimeoutError):
import time
class Deadline:
def __init__(self, seconds):
self.end = time.monotonic() + seconds
self._n = 0
def check(self):
self._n += 1
if self._n % 1024 == 0 and time.monotonic() > self.end:
raise TimeoutError("algorithm exceeded deadline")
A decorator or context-manager utility that wraps algorithms would serve users without modifying every function, and is a plausible middle ground the maintainers could adopt first.
Until native support exists, the only portable true-cancellation workaround is a separate process, since threads cannot be killed safely:
import multiprocessing as mp
def run_with_timeout(fn, args, timeout):
with mp.Pool(1) as pool:
result = pool.apply_async(fn, args)
try:
return result.get(timeout)
except mp.TimeoutError:
pool.terminate()
raise
The cost is serializing the graph across the process boundary, which is significant for large graphs — but the parent stays responsive and no half-finished thread lingers. Verify this behaves as expected on your platform with a large test graph before relying on it in production.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.