Bob
Bob

Reputation: 707

Delphi, Python4Delphi, Anaconda, Oct2Py, and Octave on Windows

I have a Delphi Win32 program that needs to run some scripts on Octave. I've taken the approach of going through Python4Delphi to get to a Python "environment", where I can write and run scripts that access Octave via Oct2Py. In order to get Oct2Py to install, I gave up doing so with my Windows Python install and went with Anaconda, which includes things like Numpy and other things needed/useful for the Oct2Py/Octave setup. After some dead ends along the way, I actually got it all working - pretty neat stuff! However, I have a bit of a performance issue here. Consider the Python script I am invoking via Python4Delphi, where I initialize Oct2Py/Octave then call a local Octave script named myScript.m:

from oct2py import Oct2Py
oc = Oct2Py()
oc.myScript(7)

When I run this script from a shell, line 1 takes about 3 seconds, and line 2 takes another; interestingly, when running from Delphi/Python4Delphi, it seems line 1 is nearly 0, while line 2 is about 1.3 seconds. In all scenarios, line 3 takes about 200 ms. Now, what I really need to do is make many calls to oc.myScript() over the course of execution, and while the 200 ms is reasonable, the 1.3 to 4 seconds on top of that for the first two lines are unacceptable. The "obvious" solution is to somehow cache the import/initialization of the connection to Octave implemented by the first two lines, and then pass oc to the later repeated oc.myScript() calls - but how?

It seems there are maybe three possibilities here:

  1. Return oc to Delphi and have it "maintain" its lifetime;
  2. Keep the TPythonEngine "instance" (not sure but it may not be an actual object, but the concept is the same) alive somehow;
  3. Demo09 from Python4Delphi includes a DLL that seems to do idea 2 as a DLL.

A related issue here is that I want to call Python and Octave scripts while maintaining some sort of history/state between calls; in other words, what I'd really like is to somehow initialize both Python and Octave environments once, then call into them many times, using the "pre-initialized" environments, rather than tearing them down and rebuilding them each time between calls. Is this feasible/reasonable/understandable?

One other thought: is it possible to skip the Python4Delphi/Python/Oct2Py and call into Octave directly from Delphi? FWIW - I'm using the Python4Delphi approach for other unrelated tasks, so that's why I started with that.

Any advice or suggestions would be greatly appreciated!

UPDATE: I was wondering whether the TPythonDelphiVar component could help, but before trying that, I just decided to be naive (or clever?). Thinking/hoping that the magic of TPythonEngine would mean that my session is maintained as part of my app's process, I ran my script as is, then I removed the first two lines, then just ran oc.MyScript (N) again, and sure enough, it just worked. My understanding is that the Python environment set up when the TPythonEngine loads the python39.dll DLL, it remains active until the engine is shut down. Therefore, every time script runs, it runs in the same environment as all earlier environments. This is great news for my app, as I can run an initial script to establish the Oct2Py/Octave connection (i.e. initialize oc here); all subsequent scripts will see the variable oc all set up and ready to go.

Upvotes: 1

Views: 276

Answers (1)

Bob
Bob

Reputation: 707

It turns out that, once loading the Python DLL via TPythonEngine, the program's process maintains the Python session, such that once the Oct2Py object is created, it lives on and may be reused by other scripts during the same session. While I may not be 100% technically correct here, to me it's helpful to think of this as running python from the shell; once you've startup up its CLI, everything you do globally is there until you exit the shell...

Upvotes: 1

Related Questions