Я работаю над научным алгоритмом (обработка изображений), который написан на 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
.
Любая помощь будет высоко ценится!
@user253751 user253751 То же самое, интерфейс зависает.
Из-за «глобальной блокировки интерпретатора» Python только один поток может выполнять код Python одновременно. Однако другие потоки могут одновременно выполнять ввод-вывод.
Если вы хотите разрешить выполнение других потоков (так же, как это делает ввод-вывод), вы можете окружить свой код следующими макросами:
Py_BEGIN_ALLOW_THREADS
// computation goes here
Py_END_ALLOW_THREADS
Другим потокам Python будет разрешено работать во время вычислений. Вы не можете получить доступ к что-нибудь из питона между этими двумя строками, поэтому соберите эти данные в порядке доPy_BEGIN_ALLOW_THREADS
.
Работает как шарм, спасибо! Я использую функции Python, которые вызываются из C++. Я проверю, не вызовет ли это каких-либо проблем. Но моя самая большая проблема была решена :)
Что, если вы вызовете Sleep в C++?