embedded python hang, is there a way to restart without restarting the process?

We have an embedded python in our application. Our application has a python script window that allows user to execute script.
It can be executed in main thread (where the UI thread is) or a separate background thread.

We found an issue that certain python libraries such as scipy (e.g. import scipy) or any libraries that deal with the UI (such as matplotlib) needs to run in the main thread. If it is being run in the background thread, it would hang (in PyRun_SimpleString() call and never returns). After it is hang, there is no way to execute any more python script except restarting the complete application.

Seems like to be a problem with the embedded python that there is no way to restart the embedded python after it hangs in PyRun_SimpleString().

I have tried the following but they did not work (results in access violation etc):

  1. Reinitialize through Py_FinalizeEx() and Py_Initialize()
  2. Create an interrupt via PyThreadState_SetAsyncExc(threadID, PyExc_Exception)
  3. Use Py_Exit(0)
  4. SetKeyboard Interrupt, e.g.:
    PyGILState_STATE state;
    state = PyGILState_Ensure();
    PyErr_SetString(PyExc_KeyboardInterrupt, “Abort”); -
    PyGILState_Release(state);
  5. Create sub-interpreter to execute subsequent script

Looks like once the (main) embedded interpreter hangs in PyRun_SimpleString(), there is no way to recover without a restart of the application.

Howdy Wlei,

Pythons multithreading capabilities are a little, huh, limited - mostly due to the GIL (global interpreter lock). The Python implementation of multithreading works more alike the veeeery oooold cooperative OSes… Round Robin like…

Did you think about using multiprocessing instead? Multiprocessing is fully supported by Python (in case you are interested in that, first have a look at the multiprocessing.Manager classes for IPC (inter process communication), they make this relatively easy; and you might want to use watchdog/heartbeats to detect and automatically restart frozen processes).

But, if you insist on using multithreading, maybe IronPython could be something for you - there, you won’t have Problems with GIL or alike, as IronPython is fully supporting (“real”) multithreading.

So, this might not exactly be the answer you are looking for but it at least contains a way to circumvent such problems by a better SW design, if you ask me - hope it helps :slight_smile:

Cheers, Dominik

Hi Dominik,

Thanks for your suggestions.

I checked out IronPython, it does not work for us because we are using Python 3.7 and above (latest). According to IronPython.net / Download, Iron python supports python 2.7 and 3.4 (in preview version).

Regarding to your suggestion to use multiprocessing, actually it is not a solution for us. We provide embedding python capability for user to execute any python script within our application using PyRun_SimpleString() (Please see 1. Embedding Python in Another Application — Python 3.7.10 documentation). We are not using python multithreading to embed python. The main thread (UI thread)and background thread that I mentioned in my original post are:

  1. If we initialize embedded python and run PyRun_SimpleString() in main thread, it will block user from using other functionalities (e.g. clicking a UI button) of our application until user’s python script has completed executing.
    1. If we initialize embedded python and run PyRun_SimpleString() in a background thread, it will not block user from using other functionalities (e.g. clicking a UI button) of our application while user’s python script is executing.

I think the issue seems to be there is not a way to restart embedded python fresh once it is hang/in error state.

Hi Wlei,

that’s true, IronPython is 2.7 only.

Is my assumption that your main program is written in Python too, right? And the user should be capable to use the / interact with the variables of said main Python program, right?

If so, do you really need to embed a whole Python interpreter or might a GUI element handling text input, alike a QTextEdit, and a connected “exec” be sufficient?

What I mean, if the user has e.g. entered “print(‘hello’)” in said text GUI element and pressed an e.g. “run” button afterwards, the main Python could do something alike:

exec(""“print(‘hello’)”"")

???

Though I am admittedly not familiar with what has changed concerning the “exec” from Python2 to Python 3, too… :slight_smile:

Cheers, Dominik

Hi Dominik,

Our application is written in C++ and we embedded python interpreter there using the following mechanism (mentioned in my last post regarding “Embedding Python in Another Application” link. For example:

Py_Initialize();
PyRun_StringFlags(script, Py_file_input, globalsDict, globalsDict, NULL);
Py_FinalizeEx()

where script is the script entered by the user in our C++ Application.

If the script cause the interpreter to hang, there is no way to recover, except restarting the whole application. If there is a way to just restart the python interpreter fresh, that will be very useful.

Thanks.

Hi Wlei,

I see…

I’ll ponder a little bit about that and come back to you as soon as I have another idea :slight_smile:

But two questions in advance: do you know, under which conditions scipy / matplotlib get frozen in the background thread? Does it happen generally or e.g. just, when some plots are shown, GUI elements are updated or alike (maybe two, not connected, main loops in just one thread?)? And: are you working on Windows, Linux or macOS (shared memory for processes work differently between OSes)?

Cheers, Dominik

Hi Dominik,

Scipy will hang upon importing the module when use in virtual environment and running it in a separate background thread. For this, I have also created an issue in github (please see Embedded python: import scipy hangs in background thread but... · Issue #13985 · scipy/scipy · GitHub). I uploaded sample code to reproduce the issue there.

matplotlib has to run in main thread as it has something to do with the UI. Anything that deals with the UI will hang when run in background thread (which is understandable). But, sometimes user may forget and accidentally run it in background thread.

There are many different ways to make embedded python hang. The above two are just examples.
The thing is once the embedded interpreter hangs, we would like an easy way to recover (e.g. ability to stop the hang embedded
python interpreter and restart it in a fresh state) instead of the need to restart the whole application.

We are using Windows.

Thanks.

Hi Wlei,

I see.

I’ll try to have a deeper look into that topic the next days (I am not familiar with the details of embedding Python yet) and come back as soon as I have another idea:)

Windows - I feared that… With Linux two processes can share memory relatively easily, with Windows, that is not possible, at least as far as I know… Doesn’t make it easier:)

CU, Cheers, Dominik

sounds good :+1: Thanks.

1 Like

Howdy Wlei,

might the following approach fit your purposes?:

I hope, the underlying idea is self explanatory - if not, do not hesitate to ask…

Cheers, Dominik

Hi Dominik,

Thanks for the suggestion. I think your idea will work. I was hoping we can solve it on the C++ embedded python side since for our application the python script is provided by user.

Thanks again!

1 Like

Hi Wlei,

Yes, I understood that - what I was trying to propose is:

take said python script provided by the user (as a string), use C++ code to dynamically insert said user-python-script-string right into the (middle of the) python-wrapper-script-string shown in the picture (e.g. at the highlighted position!) and (just) feed the resulting (user-python-script-string wrapped by python code starting and handling the threads / watchdog) string after that to PyRun_SimpleString().

This way the proposed idea can handle python scripts provided dynamically / interactively. Got the idea?

Cheers, Dominik

:+1: thanks

1 Like