I have a scenario with 2 threads:
a thread waiting for messages from a socket (embedded in a C library - blocking call is "Barra.ricevi") then putting
This is likely because your Barra
does not release the global interpreter lock (GIL) when Barra.ricevi
. You may want to check this though.
The GIL ensures that only one thread can run at any one time (limiting the usefulness of threads in a multi-processor system). The GIL switches threads every 100 "ticks" -- a tick loosely mapping to bytecode instructions. See here for more details.
In your producer thread, not much happens outside of the C-library call. This means the producer thread will get to call Barra.ricevi
a great many times before the GIL switches to another thread.
Solutions to this are to, in terms of increasing complexity:
time.sleep(0)
after adding an item to the queue. This yields the thread so that another thread can run.sys.setcheckinterval()
to lower the amount of "ticks" executed before switching threads. This is will come at the cost of making the program much more computationally expensive.multiprocessing
rather than threading
. This includes using multiprocessing.Queue
instead of Queue.Queue
.Barra
so that it does release the GIL when its functions are called.Example using multiprocessing
. Be aware that when using multiprocessing, your processes no longer have an implied shared state. You will need to have a look at multiprocessing to see how to pass information between processes.
import Barra
import multiprocessing
def threadCAN(posQu):
while True:
canMsg = Barra.ricevi("can0")
if canMsg[0] == 'ERR':
print(canMsg)
else:
print("Enqueued message", canMsg)
posQu.put(canMsg)
if __name__ == "__main__":
posQu = multiprocessing.Queue(maxsize=0)
procCan = multiprocessing.Process(target=threadCAN, args=(posQu,))
procCan.daemon = True
procCan.start()
while True:
posMsg = posQu.get()
print("Messagge from the queue", posMsg)