Andrzej Pronobis
Andrzej Pronobis

Reputation: 36136

How often are objects copied when passing across PyQt signal/slot connections?

This interesting article evaluates how often are objects copied when passed across signal/slot connections in Qt. Basically, the outcome is that when passed by const reference in C++, objects are either not copied at all (for direct connections) or copied once (for queued connections).

How about PyQt? Does the same hold? For Python objects, when a copy is made, is it a deep copy?

I am interested primarily in PyQt5 and Python 3.

Upvotes: 4

Views: 1269

Answers (1)

Andrzej Pronobis
Andrzej Pronobis

Reputation: 36136

As suggested by @ekhumoro, I did try, and surprisingly I get a different result to what the test conducted in C++ reveals. Basically, my test shows that: objects are not copied at all, even when passed across thread boundaries using QueuedConnection

Consider the following test code:

class Object2(QObject):

    def __init__(self):
        super().__init__()

    @pyqtSlot(object)
    def slot(self, data):
        print("Received data %s in thread %s" % (data, QThread.currentThread()))
        while len(data) < 10:
            time.sleep(1)
            print("Current data is %s" % data)


class Object1(QObject):

    def __init__(self):
        super().__init__()

    sig = pyqtSignal(object)

    @pyqtSlot()
    def emit_in_thread(self):
        self.data = [1]
        print("Emitting data %s in thread %s" % (self.data, QThread.currentThread()))
        self.sig.emit(self.data)
        while len(self.data) < 10:
            time.sleep(1)
            self.data += [1]
            print("Modified data to %s" % self.data)

# App
q_app = QApplication(sys.argv)

# Setup
thread = QThread()
obj1 = Object1()
obj1.moveToThread(thread)
thread.start()
obj2 = Object2()
obj1.sig.connect(obj2.slot, type=Qt.QueuedConnection)

# Emit soon
QTimer.singleShot(200, obj1.emit_in_thread)

# Run event loop
sys.exit(q_app.exec_())

The result is:

Emitting data [1] in thread <PyQt5.QtCore.QThread object at 0x7f037619f948>
Received data [1] in thread <PyQt5.QtCore.QThread object at 0x7f037619faf8>
Current data is [1]
Modified data to [1, 1]
Current data is [1, 1]
Modified data to [1, 1, 1]
Current data is [1, 1, 1]
Modified data to [1, 1, 1, 1]
Current data is [1, 1, 1, 1]
...

which shows that despite the emitting slot and the receiving slot living in different threads, they do share the data object sent over a QueuedConnection.

Upvotes: 6

Related Questions