0

I have written a program to consume data that I am sending to it via UDP packets every 10 milliseconds. I am using separate threads because it can take a variable amount of time to run the logic to process the data and if more than 10ms have elapsed I just want it to process the most recently received datagram. I am currently running a while loop and checking every millisecond for a new quote via time.sleep(0.001). I just learned that this time.sleep() is actually taking up to 16 milliseconds to process on a windows server 2019 operating system and it is delaying everything. I could just put pass instead of time.sleep but this ends up using too much CPU (I am running multiple instances of the program). Is there a way I can have the program pause and just wait for maindata.newquote == True before proceeding? The trick is I would like it to respond very quickly (in less than a millisecond) rather than waiting for the next windows timer interrupt.

class maindata:
  newquote = False
  quote = ''
  

def startquotesUDP(maindata,myaddress,port):
  UDPServerSocket = socket(family=AF_INET, type=SOCK_DGRAM)
  UDPServerSocket.bind((myaddress, port))  
  while True:
    bytesAddressPair = UDPServerSocket.recvfrom(bufferSize)
    #parse raw data
    maindata.quote = parsed_data
    maindata.newquote = True

threading.Thread(target=startquotesUDP,args=(maindata,address,port,)).start()

while True:
  if maindata.newquote == False:
    time.sleep(0.001)               #This is what I want to improve
  else:
    #process maindata.quote
    maindata.newquote = False
Chris
  • 61
  • 8
  • Use a deque between the threads? Use a wait on semaphore in the consuming thread, and the feeding thread hits the semaphore? I.e. avoid time.sleep() – DisappointedByUnaccountableMod Dec 14 '21 at 20:33
  • 1
    Does this answer your question? [How best to wake a sleeping Python thread?](https://stackoverflow.com/questions/22849606/how-best-to-wake-a-sleeping-python-thread) – Nick ODell Dec 14 '21 at 20:35

1 Answers1

1

My answer is the same as @balmy above, but I wouldn't even bother with a semaphore.

The producer just writes to a queue

while True:
    result = ...
    queue.put(result)
    sleep as necessary

The receiver can receive every result by doing

while True:
    result = queue.get()
    handle result

If you prefer only to see the most recent result sent by the producer, in case it has send multiple results since the last time you looked, then:

while True:
    result = queue.get()
    while not queue.empty():
        result = queue.get()
    handle result
Frank Yellin
  • 9,127
  • 1
  • 12
  • 22
  • I should have added that there are different things you can do depending on what you want to have happen when the producer gets ahead of the consumer. You can also specify a maximum queue size, so the producer will block if it gets too far ahead. It all depends on what you need. – Frank Yellin Dec 14 '21 at 20:51
  • This is perfect! the response time is nearly instantaneous – Chris Dec 14 '21 at 20:58
  • @balmy suggested using a `deque` not a `queue`. – martineau Dec 14 '21 at 21:20
  • @martineau. You're right. He wrote "deque" and I read "queue". That's the reason he wanted a Semaphore. In any case, I prefer using higher-level data structures and avoiding Semaphores and Condition Variables whenever possible. – Frank Yellin Dec 14 '21 at 21:28
  • 1
    `deque`s are thread-safe. – martineau Dec 14 '21 at 21:38
  • @martineau: You're right. My apologies. – Frank Yellin Dec 14 '21 at 23:49