Why does np.linalg.solve raise Bus Error when running on its own Thread (Mac M1)

Question:

Here is my configuration:
numpy: 1.6.2,
OS: macOs Monterey 12.2.1 (M1),
Python 3.10 (venv)

I am trying to run some numpy calculations with PySide GUI. Those can be heavy so I want them to run on their own thread.
But when I do this I have the following error:

[1] 38918 bus error python3 app.py

Here is my PySide code:

import sys
from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtCore import Slot, QThreadPool, QThread, QObject, Signal, QMetaObject
import numpy as np

from algorithm import main
from test_ui import Ui_MainWindow

class Worker(QObject):
    finished = Signal(int)
    progress = Signal(tuple)

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

    def run(self):
        np.linalg.solve(np.array([[0, 1], [1, 2]]), np.array([[2,3], [3,4]]))
        print("a")
        self.finished.emit(1)

class Window(QMainWindow):

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

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.pushButton.clicked.connect(self.run_ht)

        self.thread = None
        self.worker = None

        self.buildWorker()

    def run_ht(self):
        self.thread.start()

    def buildWorker(self):
        thread = QThread()
        worker = Worker()
        worker.moveToThread(thread)
        thread.started.connect(worker.run)
        worker.finished.connect(thread.quit)
        QMetaObject.connectSlotsByName(self)
        self.thread = thread
        self.worker = worker


app = QApplication(sys.argv)
window = Window()
window.show()

app.exec()

I don’t want to put all my calculations code (and it would be too long I think) but after investigation I found that the error occurs with this line:

U = np.linalg.solve(A, B)

If I run the same code without threading everythings works perfectly

Asked By: Guix

||

Answers:

I finally got it, by running a new process from the Thread:

class Worker(QThread):
    finished = Signal(float)
    progress = Signal(float)

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

        self.process = None
        self.running = True

    def run(self):
        self.running = True
        p = multiprocessing.Value('d', 0.0)
        t = multiprocessing.Value('d', 0.0)
        self.process = multiprocessing.Process(target = main, args=(p, t))
        self.process.start()
        while (p.value < 1.0) & self.running:
            self.progress.emit(p.value)
        self.process.join()
        self.finished.emit(t.value)

class Window(QMainWindow):

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

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        

        self.ui.run.clicked.connect(self.run_ht)

        self.thread = None

        self.build_worker()

    def run_ht(self):
        self.thread.start()

    def finished(self, time):
        self.thread.quit()

    def build_worker(self):
        self.thread = Worker()
        self.thread.finished.connect(self.finished)
Answered By: Guix

Same problem here on a M2 machine. Quick fix:

export MKL_NUM_THREADS=1
export NUMEXPR_NUM_THREADS=1
export OMP_NUM_THREADS=1
Answered By: user1130588
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.