freelanceprogrammers.org Forum Index » Delphi

Re: TPythonEngine / TThread


View user's profile Post To page top
mnkey007 Posted: Fri Apr 29, 2005 10:22 pm


Joined: 24 Apr 2005

Posts: 12
Re: TPythonEngine / TThread
Found the cause: gVarType is a module variable (in PythonEngine.pas)
declared just above TPythonDelphiVar`s implementation. When the
TPythonEngine instance is freed (there can only be one instance), gVarType
still refers to an already freed instance, and the next time
TPythonDelphiVar is instantiated (AFTER the TPythonEngine was freed), it is
not properly re-initialized.

I understand it should only be initialized once during the lifetime of the
TPythonEngine (seems the authors assume that equals the lifetime of the
module), but if you free and re-create TPythonEngines dynamically, it must
properly be destroyed and reset to Nil.

Solution: Put gVarType before TPythonDelphiVar.Finalize and add "gVarType :=
nil" to the end of it. Don`t free it, as it is owned by a component and
seems to be properly destroyed, but not set to nil.

It all seems unclear to me and is probably a dirty hack, but at least it
does not crash/throw any exceptions anymore, which is all I require ATM.

-Andreas

----- Original Message -----
From: "Andreas Schmid" <monkey@...>
To: <pythonfordelphi@yahoogroups.com>
Sent: Friday, April 29, 2005 4:07 PM
Subject: [pythonfordelphi] TPythonEngine / TThread


> Hi,
>
> I created a TThread-derived class that creates a TPythonEngine instance
> and
> executes Python code. It works fine. If another instance of my derived
> thread class is created (after the first one finished and is destroyed),
> however, I receive the error: `No engine defined for component ""`.
>
> Here is the code that works the first time, but not the second time it is
> called:
>
> Constructor
> =========
>
> constructor TXcComThread.Create;
> begin
> inherited Create(true);
> FHtml := TStringList.Create;
> FStrings := TStringList.Create;
>
> FPyEngine := TPythonEngine.Create(nil);
> FPyEngine.AutoFinalize := False;
> FPyEngine.LoadDll;
>
> FPyVar := TPythonDelphiVar.Create(nil);
> FPyVar.VarName := `result`;
> FPyVar.Engine := FPyEngine;
> FPyVar.Initialize;
> end;
>
> Destructor
> ========
>
> destructor TXcComThread.Destroy;
> begin
> FPyVar.Free;
> FPyEngine.Free;
>
> FStrings.Free;
> FHtml.Free;
> inherited;
> end;
>
> I suspect the Python engine and the variable are not properly destroyed
> when
> the thread finishes execution, but the thread`s constructor is called
> properly and according to the P4D example code ".Free" seems to be
> sufficient.
>
> The exception is thrown when "FPyVar.Initialize" is called:
>
> Call stack
> ========
>
> TEngineClient.CheckEngine
> TPythonType.CreateInstance
> TPythonDelphiVar.CreateVar
> TPythonDelphiVar.Initialize
>
> I`m properly doing something very wrong ...
>
> Thanks in advance,
>
> -Andreas
>
>
>
>
>
>
>
>
> To Post a message, send it to: pythonfordelphi@eGroups.com
>
> To Unsubscribe, send a blank message to:
> pythonfordelphi-unsubscribe@eGroups.com
> Yahoo! Groups Links
>
>
>
>
>
>
>
Reply with quote
Send private message
View user's profile Post To page top
mnkey007 Posted: Fri Apr 29, 2005 10:31 pm


Joined: 24 Apr 2005

Posts: 12
Re: TPythonEngine / TThread
Okay, I got a little confused: I assumed you could create multiple instances
of TPythonEngine, but now I think the only reason there is not one global
instance on the module level (e.g. created/destroyed in the PythonEngine`s
module procedures initialize and finalize) is to allow users to drop the
TPythonEngine component on a form.

So I`ll just add one module-level instance of TPythonEngine to my thread
unit. I still find the concept rather strange - why would you enforce one
instance? I know it doesn`t make much sense to create and destroy several
instances of TPythonEngine in rapid succession, but to save resources, why
not shut down the interpreter/DLL when it is not used?

-Andreas

----- Original Message -----
From: "Andreas Schmid" <monkey@...>
To: <pythonfordelphi@yahoogroups.com>
Sent: Friday, April 29, 2005 7:22 PM
Subject: Re: [pythonfordelphi] TPythonEngine / TThread


> Found the cause: gVarType is a module variable (in PythonEngine.pas)
> declared just above TPythonDelphiVar`s implementation. When the
> TPythonEngine instance is freed (there can only be one instance), gVarType
> still refers to an already freed instance, and the next time
> TPythonDelphiVar is instantiated (AFTER the TPythonEngine was freed), it
> is
> not properly re-initialized.
>
> I understand it should only be initialized once during the lifetime of the
> TPythonEngine (seems the authors assume that equals the lifetime of the
> module), but if you free and re-create TPythonEngines dynamically, it must
> properly be destroyed and reset to Nil.
>
> Solution: Put gVarType before TPythonDelphiVar.Finalize and add "gVarType
> :=
> nil" to the end of it. Don`t free it, as it is owned by a component and
> seems to be properly destroyed, but not set to nil.
>
> It all seems unclear to me and is probably a dirty hack, but at least it
> does not crash/throw any exceptions anymore, which is all I require ATM.
>
> -Andreas
>
> ----- Original Message -----
> From: "Andreas Schmid" <monkey@...>
> To: <pythonfordelphi@yahoogroups.com>
> Sent: Friday, April 29, 2005 4:07 PM
> Subject: [pythonfordelphi] TPythonEngine / TThread
>
>
>> Hi,
>>
>> I created a TThread-derived class that creates a TPythonEngine instance
>> and
>> executes Python code. It works fine. If another instance of my derived
>> thread class is created (after the first one finished and is destroyed),
>> however, I receive the error: `No engine defined for component ""`.
>>
>> Here is the code that works the first time, but not the second time it is
>> called:
>>
>> Constructor
>> =========
>>
>> constructor TXcComThread.Create;
>> begin
>> inherited Create(true);
>> FHtml := TStringList.Create;
>> FStrings := TStringList.Create;
>>
>> FPyEngine := TPythonEngine.Create(nil);
>> FPyEngine.AutoFinalize := False;
>> FPyEngine.LoadDll;
>>
>> FPyVar := TPythonDelphiVar.Create(nil);
>> FPyVar.VarName := `result`;
>> FPyVar.Engine := FPyEngine;
>> FPyVar.Initialize;
>> end;
>>
>> Destructor
>> ========
>>
>> destructor TXcComThread.Destroy;
>> begin
>> FPyVar.Free;
>> FPyEngine.Free;
>>
>> FStrings.Free;
>> FHtml.Free;
>> inherited;
>> end;
>>
>> I suspect the Python engine and the variable are not properly destroyed
>> when
>> the thread finishes execution, but the thread`s constructor is called
>> properly and according to the P4D example code ".Free" seems to be
>> sufficient.
>>
>> The exception is thrown when "FPyVar.Initialize" is called:
>>
>> Call stack
>> ========
>>
>> TEngineClient.CheckEngine
>> TPythonType.CreateInstance
>> TPythonDelphiVar.CreateVar
>> TPythonDelphiVar.Initialize
>>
>> I`m properly doing something very wrong ...
>>
>> Thanks in advance,
>>
>> -Andreas
>>
>>
>>
>>
>>
>>
>>
>>
>> To Post a message, send it to: pythonfordelphi@eGroups.com
>>
>> To Unsubscribe, send a blank message to:
>> pythonfordelphi-unsubscribe@eGroups.com
>> Yahoo! Groups Links
>>
>>
>>
>>
>>
>>
>>
>
>
>
> To Post a message, send it to: pythonfordelphi@eGroups.com
>
> To Unsubscribe, send a blank message to:
> pythonfordelphi-unsubscribe@eGroups.com
> Yahoo! Groups Links
>
>
>
>
>
>
>
Reply with quote
Send private message
View user's profile Post To page top
mnkey007 Posted: Fri Apr 29, 2005 10:45 pm


Joined: 24 Apr 2005

Posts: 12
Re: TPythonEngine / TThread
Okay the last question I have for today: Would that be correct? Or do I have
to call TPythonEngine`s Initialize method explicitly, or not call PyVar.Free
(I think it is automatically owned by PyEngine when it`s made its engine) or
additionally call UnloadDll?

initialization

PyEngine := TPythonEngine.Create(nil);
PyEngine.LoadDll;

PyVar := TPythonDelphiVar.Create(nil);
PyVar.VarName := `result`;
PyVar.Engine := PyEngine;
PyVar.Initialize;

finalization
PyVar.Free;
PyEngine.Free;
end.

Thanks!

-Andreas

----- Original Message -----
From: "Andreas Schmid" <monkey@...>
To: <pythonfordelphi@yahoogroups.com>
Sent: Friday, April 29, 2005 7:31 PM
Subject: Re: [pythonfordelphi] TPythonEngine / TThread


> Okay, I got a little confused: I assumed you could create multiple
> instances
> of TPythonEngine, but now I think the only reason there is not one global
> instance on the module level (e.g. created/destroyed in the PythonEngine`s
> module procedures initialize and finalize) is to allow users to drop the
> TPythonEngine component on a form.
>
> So I`ll just add one module-level instance of TPythonEngine to my thread
> unit. I still find the concept rather strange - why would you enforce one
> instance? I know it doesn`t make much sense to create and destroy several
> instances of TPythonEngine in rapid succession, but to save resources, why
> not shut down the interpreter/DLL when it is not used?
>
> -Andreas
>
> ----- Original Message -----
> From: "Andreas Schmid" <monkey@...>
> To: <pythonfordelphi@yahoogroups.com>
> Sent: Friday, April 29, 2005 7:22 PM
> Subject: Re: [pythonfordelphi] TPythonEngine / TThread
>
>
>> Found the cause: gVarType is a module variable (in PythonEngine.pas)
>> declared just above TPythonDelphiVar`s implementation. When the
>> TPythonEngine instance is freed (there can only be one instance),
>> gVarType
>> still refers to an already freed instance, and the next time
>> TPythonDelphiVar is instantiated (AFTER the TPythonEngine was freed), it
>> is
>> not properly re-initialized.
>>
>> I understand it should only be initialized once during the lifetime of
>> the
>> TPythonEngine (seems the authors assume that equals the lifetime of the
>> module), but if you free and re-create TPythonEngines dynamically, it
>> must
>> properly be destroyed and reset to Nil.
>>
>> Solution: Put gVarType before TPythonDelphiVar.Finalize and add "gVarType
>> :=
>> nil" to the end of it. Don`t free it, as it is owned by a component and
>> seems to be properly destroyed, but not set to nil.
>>
>> It all seems unclear to me and is probably a dirty hack, but at least it
>> does not crash/throw any exceptions anymore, which is all I require ATM.
>>
>> -Andreas
>>
>> ----- Original Message -----
>> From: "Andreas Schmid" <monkey@...>
>> To: <pythonfordelphi@yahoogroups.com>
>> Sent: Friday, April 29, 2005 4:07 PM
>> Subject: [pythonfordelphi] TPythonEngine / TThread
>>
>>
>>> Hi,
>>>
>>> I created a TThread-derived class that creates a TPythonEngine instance
>>> and
>>> executes Python code. It works fine. If another instance of my derived
>>> thread class is created (after the first one finished and is destroyed),
>>> however, I receive the error: `No engine defined for component ""`.
>>>
>>> Here is the code that works the first time, but not the second time it
>>> is
>>> called:
>>>
>>> Constructor
>>> =========
>>>
>>> constructor TXcComThread.Create;
>>> begin
>>> inherited Create(true);
>>> FHtml := TStringList.Create;
>>> FStrings := TStringList.Create;
>>>
>>> FPyEngine := TPythonEngine.Create(nil);
>>> FPyEngine.AutoFinalize := False;
>>> FPyEngine.LoadDll;
>>>
>>> FPyVar := TPythonDelphiVar.Create(nil);
>>> FPyVar.VarName := `result`;
>>> FPyVar.Engine := FPyEngine;
>>> FPyVar.Initialize;
>>> end;
>>>
>>> Destructor
>>> ========
>>>
>>> destructor TXcComThread.Destroy;
>>> begin
>>> FPyVar.Free;
>>> FPyEngine.Free;
>>>
>>> FStrings.Free;
>>> FHtml.Free;
>>> inherited;
>>> end;
>>>
>>> I suspect the Python engine and the variable are not properly destroyed
>>> when
>>> the thread finishes execution, but the thread`s constructor is called
>>> properly and according to the P4D example code ".Free" seems to be
>>> sufficient.
>>>
>>> The exception is thrown when "FPyVar.Initialize" is called:
>>>
>>> Call stack
>>> ========
>>>
>>> TEngineClient.CheckEngine
>>> TPythonType.CreateInstance
>>> TPythonDelphiVar.CreateVar
>>> TPythonDelphiVar.Initialize
>>>
>>> I`m properly doing something very wrong ...
>>>
>>> Thanks in advance,
>>>
>>> -Andreas
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>> To Post a message, send it to: pythonfordelphi@eGroups.com
>>>
>>> To Unsubscribe, send a blank message to:
>>> pythonfordelphi-unsubscribe@eGroups.com
>>> Yahoo! Groups Links
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>
>>
>>
>> To Post a message, send it to: pythonfordelphi@eGroups.com
>>
>> To Unsubscribe, send a blank message to:
>> pythonfordelphi-unsubscribe@eGroups.com
>> Yahoo! Groups Links
>>
>>
>>
>>
>>
>>
>>
>
>
>
> To Post a message, send it to: pythonfordelphi@eGroups.com
>
> To Unsubscribe, send a blank message to:
> pythonfordelphi-unsubscribe@eGroups.com
> Yahoo! Groups Links
>
>
>
>
>
>
>
Reply with quote
Send private message
View user's profile Post To page top
morgan_martinet Posted: Fri Apr 29, 2005 11:14 pm


Joined: 29 Apr 2005

Posts: 103
Re: TPythonEngine / TThread
> I understand it should only be initialized once during the lifetime of the
> TPythonEngine (seems the authors assume that equals the lifetime of the
> module), but if you free and re-create TPythonEngines dynamically, it must
> properly be destroyed and reset to Nil.
>
> Solution: Put gVarType before TPythonDelphiVar.Finalize and add "gVarType
> :=
> nil" to the end of it. Don`t free it, as it is owned by a component and
> seems to be properly destroyed, but not set to nil.

That`s right.

> It all seems unclear to me and is probably a dirty hack, but at least it
> does not crash/throw any exceptions anymore, which is all I require ATM.

Watch your memory consumption! You`ll see that it`s leaking...
See my previous mail...

Bye,

Morgan
Reply with quote
Send private message
View user's profile Post To page top
morgan_martinet Posted: Fri Apr 29, 2005 11:20 pm


Joined: 29 Apr 2005

Posts: 103
Re: TPythonEngine / TThread
Here`s an extract of Python documentation:
 



void Py_Finalize(



)



Undo all initializations
made by Py_Initialize() and subsequent use
of Python/C API functions, and destroy all sub-interpreters (see Py_NewInterpreter()
below) that were created and not yet destroyed since the last call to Py_Initialize().
Ideally, this frees all memory allocated by the Python interpreter. This is a
no-op when called for a second time (without calling Py_Initialize()
again first). There is no return value; errors during finalization are ignored.

This function is provided for a number of reasons. An
embedding application might want to restart Python without having to restart
the application itself. An application that has loaded the Python interpreter
from a dynamically loadable library (or DLL) might want to free all memory
allocated by Python before unloading the DLL. During a hunt for memory leaks in
an application a developer might want to free all memory allocated by Python
before exiting from the application.
Bugs and caveats:
The destruction of modules and objects in modules is done in random order; this
may cause destructors (__del__() methods) to fail when
they depend on other objects (even functions) or modules. Dynamically loaded
extension modules loaded by Python are not unloaded. Small amounts of memory
allocated by the Python interpreter may not be freed (if you find a leak,
please report it). Memory tied up in circular references between objects is not
freed. Some memory allocated by extension modules may not be freed. Some
extensions may not work properly if their initialization routine is called more
than once; this can happen if an application calls Py_Initialize()
and Py_Finalize()
more than once.
 
Reply with quote
Send private message
View user's profile Post To page top
morgan_martinet Posted: Fri Apr 29, 2005 11:29 pm


Joined: 29 Apr 2005

Posts: 103
Re: TPythonEngine / TThread
> Okay, I got a little confused: I assumed you could create multiple
> instances
> of TPythonEngine, but now I think the only reason there is not one
global
> instance on the module level (e.g. created/destroyed in the
PythonEngine`s
> module procedures initialize and finalize) is to allow users to
drop the
> TPythonEngine component on a form.
Right.
 
> So I`ll just add one module-level instance of TPythonEngine to my
thread
> unit. I still find the concept rather strange - why would you
enforce one
> instance? I know it doesn`t make much sense to create and destroy
several
> instances of TPythonEngine in rapid succession, but to save
resources, why
> not shut down the interpreter/DLL when it is not used?
It`s because of Python itself!
The component TPythonEngine gives the
illusion that it`s a real component that you can drop where/when you want and
have separate engines working autonomously, but that`s not the case! Python is
made of global functions only, where you initialize the engine, then execute
scripts. That`s all.
To overcome this problem, they introduced
the notion of global lock, interpreter, but that`s a mess! You have to
initialize/switch between them...
Anyway, have a look at this: http://docs.python.org/api/threads.html
 
So, the best way to use Python is in a
single thread environment, and have it initialized only once.
You can still investigate other ways and
report us your success/troubles…
 
Bye,
 
Morgan
 
 
Reply with quote
Send private message
View user's profile Post To page top
morgan_martinet Posted: Fri Apr 29, 2005 11:32 pm


Joined: 29 Apr 2005

Posts: 103
Re: TPythonEngine / TThread
> Okay the last question I have for today: Would that be correct? Or do I
> have
> to call TPythonEngine`s Initialize method explicitly, or not call
> PyVar.Free
> (I think it is automatically owned by PyEngine when it`s made its engine)
> or
> additionally call UnloadDll?
>
> initialization
>
> PyEngine := TPythonEngine.Create(nil);
> PyEngine.LoadDll;
>
> PyVar := TPythonDelphiVar.Create(nil);
> PyVar.VarName := `result`;
> PyVar.Engine := PyEngine;
> PyVar.Initialize;
>
> finalization
> PyVar.Free;
> PyEngine.Free;
> end.

LoadDll will call Initialize in the AfterLoad method, so that`s fine.
When you destroy any Python client like TPythonDelphiVar, it will
automatically finalize the engine as it would be too dangerous to continue.
So, that`s fine again.

Note that you can also create the PyVar object before invoking LoadDll. In
that case, you don`t need to initialize PyVar by yourself:


PyEngine := TPythonEngine.Create(nil);

PyVar := TPythonDelphiVar.Create(nil);
PyVar.VarName := `result`;
PyVar.Engine := PyEngine;

// create as many clients as you want

PyEngine.LoadDll; // last instruction

Bye,

Morgan
Reply with quote
Send private message
View user's profile Post To page top
mnkey007 Posted: Sat Apr 30, 2005 12:23 am


Joined: 24 Apr 2005

Posts: 12
Re: TPythonEngine / TThread
Thanks for your answers, Morgan! Highly appreciated!

-Andreas


----- Original Message -----
From: "Morgan Martinet" <yahoo@...>
To: <pythonfordelphi@yahoogroups.com>
Sent: Friday, April 29, 2005 8:32 PM
Subject: RE: [pythonfordelphi] TPythonEngine / TThread


>> Okay the last question I have for today: Would that be correct? Or do I
>> have
>> to call TPythonEngine`s Initialize method explicitly, or not call
>> PyVar.Free
>> (I think it is automatically owned by PyEngine when it`s made its engine)
>> or
>> additionally call UnloadDll?
>>
>> initialization
>>
>> PyEngine := TPythonEngine.Create(nil);
>> PyEngine.LoadDll;
>>
>> PyVar := TPythonDelphiVar.Create(nil);
>> PyVar.VarName := `result`;
>> PyVar.Engine := PyEngine;
>> PyVar.Initialize;
>>
>> finalization
>> PyVar.Free;
>> PyEngine.Free;
>> end.
>
> LoadDll will call Initialize in the AfterLoad method, so that`s fine.
> When you destroy any Python client like TPythonDelphiVar, it will
> automatically finalize the engine as it would be too dangerous to
> continue.
> So, that`s fine again.
>
> Note that you can also create the PyVar object before invoking LoadDll. In
> that case, you don`t need to initialize PyVar by yourself:
>
>
> PyEngine := TPythonEngine.Create(nil);
>
> PyVar := TPythonDelphiVar.Create(nil);
> PyVar.VarName := `result`;
> PyVar.Engine := PyEngine;
>
> // create as many clients as you want
>
> PyEngine.LoadDll; // last instruction
>
> Bye,
>
> Morgan
>
>
>
>
>
> To Post a message, send it to: pythonfordelphi@eGroups.com
>
> To Unsubscribe, send a blank message to:
> pythonfordelphi-unsubscribe@eGroups.com
> Yahoo! Groups Links
>
>
>
>
>
>
>
Reply with quote
Send private message
Post new topic Reply to topic
Display posts from previous:   
 

All times are GMT
Page 1 of 1
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
Freelace Website Designer - Customer web design and software building.
China Wholesale - Electronics Products
Character Studio - Tutorials and Help