Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MRG] Improve DUL performance #651

Merged
merged 13 commits into from Dec 22, 2021
3 changes: 3 additions & 0 deletions .gitignore
Expand Up @@ -93,3 +93,6 @@ ENV/

# Rope project settings
.ropeproject

# PyCharm
.idea
15 changes: 13 additions & 2 deletions pynetdicom/dul.py
Expand Up @@ -378,14 +378,23 @@ def run_reactor(self) -> None:
# Main DUL loop
self._idle_timer.start()
self.socket = cast("AssociationSocket", self.socket)
sleep = False

while True:
# Let the assoc reactor off the leash
if not self.assoc._dul_ready.is_set():
self.assoc._dul_ready.set()
# When single-stepping the reactor, sleep between events so that
# test code has time to run.
sleep = True

# This effectively controls how quickly the DUL does anything
time.sleep(self._run_loop_delay)
if sleep:
# If there were no events to process on the previous loop,
# sleep before checking again. Otherwise check immediately.

# Setting _run_loop_delay higher will use less CPU when idle, but will also
# increases the latency to respond to new requests.
time.sleep(self._run_loop_delay)

if self._kill_thread:
break
Expand Down Expand Up @@ -426,9 +435,11 @@ def run_reactor(self) -> None:
event = self.event_queue.get(block=False)
# If the queue is empty, return to the start of the loop
except queue.Empty:
sleep = True
continue

self.state_machine.do_action(event)
sleep = False

def send_pdu(self, primitive: _PDUPrimitiveType) -> None:
"""Place a primitive in the provider queue to be sent to the peer.
Expand Down
13 changes: 13 additions & 0 deletions pynetdicom/events.py
Expand Up @@ -84,6 +84,10 @@ class NotificationEvent(NamedTuple):
is_intervention: bool = False
is_notification: bool = True

def __str__(self) -> str:
mself marked this conversation as resolved.
Show resolved Hide resolved
"""String representation of the class."""
return self.name


# pylint: disable=line-too-long
EVT_ABORTED = NotificationEvent("EVT_ABORTED", "Association aborted")
Expand Down Expand Up @@ -135,6 +139,10 @@ class InterventionEvent(NamedTuple):
is_intervention: bool = True
is_notification: bool = False

def __str__(self) -> str:
mself marked this conversation as resolved.
Show resolved Hide resolved
"""String representation of the class."""
return self.name


EVT_ASYNC_OPS = InterventionEvent("EVT_ASYNC_OPS", "Asynchronous operations negotiation requested") # noqa
EVT_SOP_COMMON = InterventionEvent("EVT_SOP_COMMON", "SOP class common extended negotiation requested") # noqa
Expand Down Expand Up @@ -421,6 +429,11 @@ def __init__(
)
setattr(self, kk, vv)

def __str__(self) -> str:
mself marked this conversation as resolved.
Show resolved Hide resolved
"""String representation of the class."""
return 'Event(event={}, message_id={}, timestamp={}, is_cancelled={})'\
mself marked this conversation as resolved.
Show resolved Hide resolved
.format(self.event, self.message_id, self.timestamp, self.is_cancelled)

@property
def action_information(self) -> Dataset:
"""Return an N-ACTION request's `Action Information` as a *pydicom*
Expand Down