Python Threading

Hello,

I am trying to gather data from a camera and a sensor using one loop for each and python Threading. The problem is that when I run each loop independently they work, but at the same time using threading only one of the two works and if one crashes, then the other starts working. I am using the powermode MODE30ALL and the exact same code works fine on a classic computer.

Thanks,

Gabriel

Hi,

Could you share a sample code with us to reproduce this?
We can use multi-threading in C++ well but don’t have too much experience on python threading.

Thanks.

Hello,

Here is a sample code, the requirements are to have a camera plugged to the Xavier and have the pyqtgraph python and opencv library installed.

import pyqtgraph as pg
from pyqtgraph.Qt import QtGui
import cv2
import time
import random
from threading import Thread

def loop1():
    #Plot setup
    app = QtGui.QApplication([])
    pg.setConfigOption('background','w')
    win = pg.GraphicsWindow(title="2D scatter plot")
    p = win.addPlot()
    p.setXRange(0,1)
    p.setYRange(0,1)
    s = p.plot([],[],pen=None,symbol='o')
    
    while True:
        #Update plot with random values
        x = [random.random()]
        y = [random.random()]

        s.setData(x,y)
        QtGui.QApplication.processEvents()
        time.sleep(0.05)
        
def loop2():
    video = cv2.VideoCapture(0)
    while True:
        #Display camera feed
        ret, frame  = video.read()
        cv2.imshow('frame', frame)
        cv2.waitKey(1)
        
if __name__ == '__main__':

    Thread(target = loop1).start()
    Thread(target = loop2).start()

When I run each loop individually, they work well, but using Threading, only the graph displays and I get no camera feed.

I also tried to run this code on a my laptop (Windows 10) and it works perfectly with the same python version (3.6.8) and the same camera.

Thanks,

Gabriel

The python threading module does not release the GIL (global interpreter lock) so even if multiple OS threads are launched, only one is scheduled to execute at a time (the idea is to context shift with sleep(), spending most of your time waiting on external things). To actually do more than one thing at once in parallel, you must use the multiprocessing module which launches multiple instances of the python interpreter or write a c extension (or use Cython to do so) which releases the gil, does stuff in parallel, and re-acquires it (not doing so segfaults). Rule of thumb: the threading module (or async) is for stuff that’s IO bound while multiprocessing is for stuff that’s CPU bound.

More about this:

http://jessenoller.com/blog/2009/02/01/python-threads-and-the-global-interpreter-lock
https://learn-gevent-socketio.readthedocs.io/en/latest/general_concepts.html
https://lwn.net/Articles/726600/

No guarantees it will fix it, but I think the problem is there is no sleep() in your second loop to context switch. I am not sure if cv2.waitkey will do the trick.

Thank you so much for your response mdegans. Using the multiprocessing module did the trick but I think I’ll switch my code to c++ so I won’t be in trouble again.

You’re welcome. I find myself doing that more and more recently for these kinds of reasons.