owillebo
owillebo

Reputation: 665

Python Event::wait with timeout gives delay

Running Python 2.6 and 2.7 on Windows 7 and Server 2012

Event::wait causes a delay when used with a timeout that is not triggered because event is set in time. I don't understand why.

Can someone explain?

The following program shows this and gives a possible explanation;

'''Shows that using a timeout in Event::wait (same for Queue::wait) causes a
delay. This is perhaps caused by a polling loop inside the wait implementation. 
This polling loop sleeps some time depending on the timeout. 
Probably wait timeout > 1ms => sleep = 1ms 
A wait with timeout can take at least this sleep time even though the event is
set or queue filled much faster.''' 
import threading 

event1 = threading.Event() 
event2 = threading.Event() 

def receiver(): 
  '''wait 4 event2, clear event2 and set event1.''' 
  while True: 
    event2.wait() 
    event2.clear() 
    event1.set() 

receiver_thread = threading.Thread(target = receiver) 
receiver_thread.start() 

def do_transaction(timeout): 
  '''Performs a transaction; clear event1, set event2 and wait for thread to set event1.''' 
  event1.clear() 
  event2.set() 
  event1.wait(timeout = timeout) 

while True: 
  # With timeout None this runs fast and CPU bound. 
  # With timeout set to some value this runs slow and not CPU bound. 
  do_transaction(timeout = 10.0) 

Upvotes: 3

Views: 1315

Answers (1)

Justin Francis
Justin Francis

Reputation: 248

Looking at the source code for wait() method of the threading.Condition class, there are two very different code paths. Without a timeout, we just wait on a lock forever, and when we get the lock, we return immediately.

However, with a timeout you cannot simply wait on the lock forever, and the low-level lock provides no timeout implementation. So the code sleeps for exponentially longer periods of time, after each sleep checking if the lock can be acquired. The relevant comment from the code:

# Balancing act:  We can't afford a pure busy loop, so we
# have to sleep; but if we sleep the whole timeout time,
# we'll be unresponsive.  The scheme here sleeps very
# little at first, longer as time goes on, but never longer
# than 20 times per second (or the timeout time remaining).

So in an average scenario where the condition/event cannot is not notified within a short period of time, you will see a 25ms delay (a random incoming event will arrive on average with half the max sleep time of 50ms left before the sleep ends).

Upvotes: 2

Related Questions