I am developing an application in PyQt (primarily Windows but with the future intention to go multiplatform) which focuses on processing certain numerical data, so the core is basically built around numpy arrays and matplotlib charts. However I wanted to make parts of the system Python scriptable, allowing the users to tweak the data processing a bit. The script code they write is stored in a string and it just needs to pass in and out some parameters of arbirtary types. And add some error handling as well... This can be achieved in a very simple way in Python, like in the code fragment here:
global_dict = {} # values could go in here
local_dict = {} # values could go in here
try:
exec(script_code, global_dict, local_dict)
value = local_dict[variable_name] # value out
#etc...
The problem is that the user scripts are out of my control, the user can write whatever they like and they can take significant time to execute which could freeze GUI. So I needed to go multithreading. I already have a working solution. I use a class which inherits from QtCore.QRunnable runs and the code above asynchronously. It works fine and correctly notifies the GUI thread when the script is finished, passes the results and destroys the thread. But still I have three serious problems:
1) a crucial problem: how to abort the script execution? Although the asynchronous script does not freeze GUI, it can be very long or even infinite. And the user certainly must have the option to abort the execution without having to terminate the whole application. This does not seem to be possible with QRunnable. So I thinked about switching from QRunnable to QThread which has terminate method. However it is strictly not recommended using this method. It is very questionable how would the application recover from the termination of one of its threads, for example what would happen to reference counting with the objects passed into the script. Is this problem even solvable? I do not know... maybe there is a miraculous solution that I do not see. Could Python multiprocessing module help?
2) an important problem: as users can pass data in and out from their scripts, which is done by reference, they can also change the data. In Python multithreading GIL ensures that no two threads write to the same data at the same time but it might happen that the data is already being processed or displayed also in another part of the application. So I would need to have the inputs into the script read only, throwing exception when user attempts to write in it. Is it even possible?
3) a nice-to-have-solved-but-can-live-with-it problem: Sometimes several scripts can be executed at the same time. Due to Python's GIL all threads are executed in one interpreter and one processor core only. This might be a limitation for the performance. As I learned, for benefiting from multiple processor cores I would need to switch from multithreading to multiprocessing. But how to do that with the given scenario? Is it even compatible with PyQt architecture? How to pass values in and out? How to terminate?
Maybe I am asking too much, maybe my wishes are not from this reality. Nevertheless I would be very grateful for any hint or advice or sources to look into.