From c1b85ec74d80b673b22d729122445e5eb08bdbe3 Mon Sep 17 00:00:00 2001 From: Michael Bynum Date: Wed, 24 Apr 2024 08:57:27 -0600 Subject: [PATCH 1/2] highspy: release python GIL when calling run --- highspy/highs_bindings.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/highspy/highs_bindings.cpp b/highspy/highs_bindings.cpp index 5c64109adb..1f4e9c0423 100644 --- a/highspy/highs_bindings.cpp +++ b/highspy/highs_bindings.cpp @@ -551,6 +551,15 @@ std::tuple highs_getRowByName(Highs* h, } +HighsStatus highs_run(Highs* h) +{ + py::gil_scoped_release release; + HighsStatus status = h->run(); + py::gil_scoped_acquire(); + return status; +} + + PYBIND11_MODULE(highspy, m) { // enum classes @@ -835,7 +844,7 @@ PYBIND11_MODULE(highspy, m) { .def("writeBasis", &Highs::writeBasis) .def("postsolve", &highs_postsolve) .def("postsolve", &highs_mipPostsolve) - .def("run", &Highs::run) + .def("run", &highs_run) .def("presolve", &Highs::presolve) .def("writeSolution", &highs_writeSolution) .def("readSolution", &Highs::readSolution) From e9f423506dc14a7a6c2b2eecf6c889533e3f95d2 Mon Sep 17 00:00:00 2001 From: Michael Bynum Date: Mon, 19 Aug 2024 13:25:18 -0600 Subject: [PATCH 2/2] run solve in background thread so that keyboard interrupt works --- src/highspy/highs.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/highspy/highs.py b/src/highspy/highs.py index 9abf20ea26..456708e3c2 100644 --- a/src/highspy/highs.py +++ b/src/highspy/highs.py @@ -36,6 +36,13 @@ from itertools import groupby from operator import itemgetter from decimal import Decimal +from threading import Thread + + +class _ThreadingResult: + def __init__(self): + self.out = None + class Highs(_Highs): """HiGHS solver interface""" @@ -51,10 +58,20 @@ def __init__(self): # Silence logging def silent(self): super().setOptionValue("output_flag", False) + + def _run(self, res): + res.out = super().run() + + def run(self): + return self.solve() # solve def solve(self): - return super().run() + res = _ThreadingResult() + t = Thread(target=self._run, args=(res,)) + t.start() + t.join() + return res.out # reset the objective and sense, then solve def minimize(self, obj=None):