Расширение CPython с использованием omp замораживает пользовательский интерфейс Qt

Я работаю над научным алгоритмом (обработка изображений), который написан на C++ и использует много распараллеливания, обрабатываемого OpenMP. Мне нужно, чтобы его можно было вызывать из Python, поэтому я создал пакет CPython, который обрабатывает оболочку алгоритма. Теперь мне нужен пользовательский интерфейс, так как взаимодействие с пользователем необходимо для инициализации некоторых вещей. Моя проблема в том, что пользовательский интерфейс зависает, когда я запускаю алгоритм. Я запускаю алгоритм в отдельном потоке, так что это не должно быть проблемой (я даже доказал это, заменив вызов функции на time.sleep, и он отлично работает, не вызывая зависаний). Для тестирования я сократил пользовательский интерфейс до двух кнопок: одна для запуска алгоритма, а другая просто для вывода какой-то случайной строки в консоль (для проверки взаимодействия с пользовательским интерфейсом).
Я также испытал что-то действительно странное. Если я начал двигать мышь, затем нажимал кнопку, чтобы начать вычисления, и после этого продолжал двигать мышь непрерывно, пользовательский интерфейс не зависал, поэтому наведение курсора на кнопки придавало им обычный голубоватый оттенок в стиле Windows. Но если я переставал перемещать мышь на несколько секунд по окну приложения, нажимал кнопку или переключался в другое окно, пользовательский интерфейс снова зависал. Еще более странно, что пользовательский интерфейс оставался активным, если я держал мышь за пределами окна приложения.

if __name__ == "__main__":
    from PyQt5.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget
    from PyQt5.QtCore import QThread, QObject, pyqtSignal
    import time
    from CustomAlgorithm import Estimator # my custom Python package implemented in C++

    class Worker(QObject):
        finished = pyqtSignal()

        def run(self):
            estimator = Estimator()
            estimator.calculate()
            # if the above two lines are commented, and the next line is uncommented,
            # everything's fine
            # time.sleep(5)
            print("done")

    app = QApplication([])
    thread = QThread()
    window = QWidget()
    layout = QVBoxLayout()
    # button to start the calculation
    btn = QPushButton("start")
    layout.addWidget(btn)
    btn.clicked.connect(thread.start)

    # button to print some text to console
    btn2 = QPushButton("other button")
    layout.addWidget(btn2)
    btn2.clicked.connect(lambda: print("other button clicked"))
    window.setLayout(layout)

    # handling events
    worker = Worker(app)
    worker.moveToThread(thread)
    thread.started.connect(worker.run)
    worker.finished.connect(thread.quit)
    worker.finished.connect(worker.deleteLater)
    thread.finished.connect(thread.deleteLater)
    window.show()
    app.exec_()

Я пробовал несколько вариантов использования потоков, таких как threading.Thread, multiprocessing.Process, PyQt5.QtCore.QThread (как показано выше), даже рабочую реализацию napari, но результат был таким же. Я даже пытался удалить omp из кода, на всякий случай, если он каким-то образом мешает потокам Python, но это не помогло.

Что касается причины, по которой я использую python, так это то, что конечная цель — сделать мою реализацию доступной в napari.

Любая помощь будет высоко ценится!

Что, если вы вызовете Sleep в C++?

user253751 22.03.2022 16:27

@user253751 user253751 То же самое, интерфейс зависает.

bauerdavid 22.03.2022 16:38
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
2
27
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Из-за «глобальной блокировки интерпретатора» Python только один поток может выполнять код Python одновременно. Однако другие потоки могут одновременно выполнять ввод-вывод.

Если вы хотите разрешить выполнение других потоков (так же, как это делает ввод-вывод), вы можете окружить свой код следующими макросами:

Py_BEGIN_ALLOW_THREADS

// computation goes here

Py_END_ALLOW_THREADS

Другим потокам Python будет разрешено работать во время вычислений. Вы не можете получить доступ к что-нибудь из питона между этими двумя строками, поэтому соберите эти данные в порядке доPy_BEGIN_ALLOW_THREADS.

Справка

Работает как шарм, спасибо! Я использую функции Python, которые вызываются из C++. Я проверю, не вызовет ли это каких-либо проблем. Но моя самая большая проблема была решена :)

bauerdavid 22.03.2022 16:53

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