PyQt и QThreads: отдельные потоки все еще замораживают основной поток GUI?

Я пытаюсь сделать какую-то работу в отдельном потоке, в Python. Я использую PyQt, поэтому мои темы - QThreads.

Сама работа включает в себя загрузку больших изображений с помощью PIL и преобразование изображения в QImage.

Вот пример некоторого кода, который загружает изображение снова и снова в рабочем потоке:

class testThread(QtCore.QThread):
    def run(self):
        while True:
            im = Image.open('c:\zheadline.tif')
            try:
                imgData = ImageQt.ImageQt(im)
                print (imgData.width())
            except:
                print ("Image load error")

Изображение довольно большое (16 КБ), поэтому его загрузка может занять пару секунд. Тем не менее, в течение этого времени графический интерфейс пользователя перестает отвечать на запросы, часто зависая на несколько сотен миллисекунд.

Почему это? Моя машина имеет 16 ядер, поэтому нет причин, по которым работа из одного потока приведет к замедлению работы всех остальных, верно?

По сути, я хочу загружать эти большие изображения в фоновом режиме, не прерывая работу пользователя. У кого-нибудь есть идеи, как я могу перенести основную работу в другой поток, не нарушая основной поток GUI вообще?

Немного другой информации: я запускаю QThreads с помощью thread.start(). Кроме того, графический интерфейс не полностью зависает во время загрузки... он просто становится чрезвычайно медленным и медленным, периодически зависая.

2 ответа

Решение

Интерпретатор python может запускаться только в одном потоке за раз (читайте о глобальной блокировке интерпретатора), поэтому, вероятно, один или оба из Image.open и ImageQt.ImageQt выполняют большую работу в python, не выпуская GIL.

Возможным решением является загрузка изображений в отдельном процессе и передача данных через общую память. Недавно я сделал что-то подобное: http://bazaar.launchpad.net/~luke-campagnola/pyqtgraph/dev/view/head:/widgets/RemoteGraphicsView.py. Смотрите метод 'remoteSceneChanged', чтобы узнать, как QImage был восстановлен из разделяемой памяти.

За "Python, Threads & Qt: Boom!" - Тейо Хольцер (Kiwi Pycon 2019), многопоточность с Qt / qthread - Джузеппе Д'Анджело и документы Qt, вы не можете вызывать следующие объекты вне основного потока:

  1. QWidget
  2. QQuickItem
  3. QPixmap
  4. Как правило, все события рисования / видимого / виджета

Следовательно, я подозреваю, что прохождение im к ImageQt.ImageQt(im)во вторичном потоке вызывает проблему. Я бы рекомендовал сделать это в основном потоке и просто открыть файл ( Image.open) в вашей QThread.

Другие вопросы по тегам