pyqt gui locked when calling cython function from QThread.run

706 views Asked by At

In PyQt4 I want to execute code with no lock gui. I use QThread and emit signal for gui update. But if i call cython function in QThread.run gui will be locked.

class Runner(QtCore.QThread):
    iter = QtCore.pyqtSignal(int)

    def __init__(self):
        QtCore.QThread.__init__(self)

    def do_something(self):
        beg = time.time()
        s = 0.0
        while time.time() - beg < 1:
            s += math.sqrt(1000)

    def run(self):
        for it in xrange(10):
            # no lock gui
            #self.do_something()

            # lock gui
            cython_unit.do_something()

            self.iter.emit(it + 1)

cython_unit.pyx:

import math
import time
def do_something():
    beg = time.time()
    s = 0.0
    while time.time() - beg < 1:
        s += math.sqrt(1000)

test project is here: https://github.com/ombschervister/test

1

There are 1 answers

0
DavidW On BEST ANSWER

Due to the GIL (global interpretter lock) only one Python instance can execute at once. How Python chooses to share time between threads depends a bit on the version of Python but it's substantially based on how many Python bytecodes have been executed (see https://docs.python.org/3.0/library/sys.html#sys.setcheckinterval).

I'd guess that since Cython doesn't actually run any Python bytecodes it never releases the GIL, and hence your display will lock. You can release the GIL manually using with nogil. In the worst case I'd think that adding:

with nogil:
  pass

to your loop will work. However, some of your code could definitely be done without the GIL (i.e. not using python features):

from libc.math cimport sqrt # don't use Python math module
import time

def do_something():
   beg = time.time()
   cdef double s = 0 # typed as a double, not a python object
   while time.time() - beg < 1:
      with nogil:
        s += sqrt(1000) # now using C sqrt, not the python one

You could also use the libc time functions and wrap pretty much the whole function in a with nogil block if you wanted, in which case it shouldn't block the GUI at all.