pyscripter / python4delphi

Free components that wrap up Python into Delphi and Lazarus (FPC)
MIT License
895 stars 307 forks source link

numpy and TTask #457

Closed KhurshedUlugov closed 6 months ago

KhurshedUlugov commented 6 months ago

Hi! Question on Python4Delphi. When calling a script inside TTask, the script with the numpy module is not loaded and the script hangs at the "import numpy" line. Without TTask everything is fine, as well as without numpy in the Python script.

>     task := TTask.Create(
>        procedure
>        begin
>          uf_WriteToLog('Script is running',[PyFileName]);
>          GetPythonEngine.ExecFile(PyFileName);
> 
>          if task.Status = TTaskStatus.Canceled then
>             //If canceled, exit the loop.
>             Exit;
>        end);
>     task.Start;

i.e. everything works in the main thread, but in a separate thread it is a problem. The problem so far is only with numpy. If the script does not contain this library, everything is fine. Who has encountered this problem? Please help me

pyscripter commented 6 months ago

Please see https://github.com/pyscripter/python4delphi/wiki/PythonThreads

KhurshedUlugov commented 6 months ago

Unfortunately, nothing works. None of the methods given in the article. There is simply no response. I have logging, but nothing is written in the log.

What am I doing wrong? Python embedded version is 3.8. Delphi 11.3

Here is my code:

    ThreadPythonExec(
    procedure
    begin
      GetPythonEngine.ExecFile(PyFileName);
    end{, nil, false, emNewInterpreter});

    Task := TTask.Create(
        procedure
        var
          Py: IPyEngineAndGIL;
        begin
          Py := SafePyEngine;
          Py.PythonEngine.ExecFile(PyFileName);
        end);
    Task.Start;
pyscripter commented 6 months ago

Are you doing this?

You should call Py_Begin_Allow_Threads in your main thread, after the python DLL was loaded, for example in your FormCreate event handler.

Also have a look at Demo 33.

KhurshedUlugov commented 6 months ago

Thanks for the help, it really worked. But the problem hasn't completely disappeared. I call TPythonThread.Py_Begin_Allow_Threads when I create a form. I also call TPythonThread.Py_End_Allow_Threads when closing the form. Everything is fine, everything works fine. But if I close the form and start the form again, then there is a problem in the script with the numpy module again(other packages seem to be fine). I get an error:

C:\A\34\s/Objects/structsseq.c:398: bad argument to internal function

When I close the form, I unload the dll:

procedure TfrmScripts.FormDestroy(Sender: TObject); begin PyEngine.UnloadDll; TPythonThread.Py_End_Allow_Threads; // Acquire the GIL FreeAndNil(PyEngine); inherited; end;

What am I doing wrong?

pyscripter commented 6 months ago

Why do you free the engine?

Destroying and recreating the engine is not a good idea.

KhurshedUlugov commented 6 months ago

I create PythonEngine dynamically on form create. But it doesn't make any difference. Even if I use TPythonEngine component (put ting it on a form, so I don't need destroy it on closing form), still this error occurs. I have an MDI application. What do you recommend?

Put TPythonEngine component in Data Module?

Destroying and recreating the engine is not a good idea. Why?

pyscripter commented 6 months ago

It makes no difference if you put the PythonEngine on a Form or a DataModule. Are you releasing the GIL before running python code again?

I am not sure what causes the error in your program, but this is not a P4D issue. You may get some help if you use the Support forum.

KhurshedUlugov commented 6 months ago

Are you releasing the GIL before running python code again?

on form create: TPythonThread.Py_Begin_Allow_Threads;

on form destroy: TPythonThread.Py_End_Allow_Threads;