Wed, Dec 4, 2:11 PM CST

Renderosity Forums / Poser Python Scripting



Welcome to the Poser Python Scripting Forum

Forum Moderators: Staff

Poser Python Scripting F.A.Q (Last Updated: 2024 Dec 02 3:16 pm)

We now have a ProPack Section in the Poser FreeStuff.
Check out the new Poser Python Wish List thread. If you have an idea for a script, jot it down and maybe someone can write it. If you're looking to write a script, check out this thread for useful suggestions.

Also, check out the official Python site for interpreters, sample code, applications, cool links and debuggers. This is THE central site for Python.

You can now attach text files to your posts to pass around scripts. Just attach the script as a txt file like you would a jpg or gif. Since the forum will use a random name for the file in the link, you should give instructions on what the file name should be and where to install it. Its a good idea to usually put that info right in the script file as well.

Checkout the Renderosity MarketPlace - Your source for digital art content!



Subject: A multithreading in Poser Python.


JTrout ( ) posted Wed, 02 November 2011 at 11:33 AM · edited Wed, 04 October 2023 at 12:17 PM

Hi

I can't implement multithreading code in PoserPython.
For example, Poser freezes when it runs the following simple script.

#----------------
import time
import threading

class MyThread(threading.Thread):
    def init(self):
        threading.Thread.init(self)
        self.setDaemon(True)
        
    def run(self):
        print "Start1n"
        for i in range(10):
            print 'Thread1: %in' % i
            time.sleep(2)
        print "Completed1n"

def main():
    thread = MyThread()
    thread.start()
    
    print "Start0n"
    for i in range(10):
        print 'Thread0: %in' % i
        time.sleep(2)
    print "Completed0n"
    
main()
#----------------

Of course, that works properly outside Poser as expected.
I tried with PoserPro2010.  

Please tell me, if there is a solution.

Thank you


bagginsbill ( ) posted Wed, 02 November 2011 at 11:53 AM

Only one thread is allowed to use the UI, or in fact use the Poser API at all. Your print statement is a crash-maker, since it doesn't go to the OS, but rather to the wx API.

Also, you should know something about multi-threading in Python (in general, not specific to Poser). It's not multi-core. Two threads do not run literally at the same time. Only one thread runs within a process, because there is a mutex needed to gain access to the interpreter. Look up Global Interpreter Lock.

So - while you do create actual multiple threads, and these can interrupt each other and cause crashes due to non-atomic API calls, you get zero performance benefit. It can be helpful for keeping track of multiple complex activities with waiting being handled automatically, but that's all it's good for.


Renderosity forum reply notifications are wonky. If I read a follow-up in a thread, but I don't myself reply, then notifications no longer happen AT ALL on that thread. So if I seem to be ignoring a question, that's why. (Updated September 23, 2019)


JTrout ( ) posted Wed, 02 November 2011 at 1:06 PM

Thank you very much for the clear answer.  

I understood it.
I must think about another method if those are the specifications of Poser.

Because a so-called parallel computation is not my purpose, I do not care even about imitative thread of Python.
However, I grope for other method, at any rate.
 
As for me, I  wanted to implement the following user interface.

  • There is long management to proceed automatically, and user does specific operation optionally.
  • Or, a user needs to do nothing.  

Actually, my Python program which has such a user interface is working suitably outside Poser.
Of course a thread-safe mechanism is made consciously.

At any rate, I must reconsider design fundamentally to work it into Poser.

Thank you again.


bagginsbill ( ) posted Wed, 02 November 2011 at 5:34 PM

You want to use a thread safe queue where background threads can post strings for display, but not actually display them.

Then, set up a timer from the UI thread that pulls messages from the queue and shows them in a wx dialog window. This way you can write code to do long background work and not worry about output from there.


Renderosity forum reply notifications are wonky. If I read a follow-up in a thread, but I don't myself reply, then notifications no longer happen AT ALL on that thread. So if I seem to be ignoring a question, that's why. (Updated September 23, 2019)


JTrout ( ) posted Thu, 03 November 2011 at 7:01 AM

I noticed that now by your suggestion though I was a little mistaken.

I was mistaken when multithreading of Python in Poser was unacceptable.  
A print statement for debugging had been included in the code which worried me.
I should have noticed it when a print statement was used for a last example.  
(I may be very tired now by the long programming work.)

The following code actually works in Poser.

#--------------------
import time
import threading
import Queue
        
class MyThread(threading.Thread):
    def init(self, id, aFiFo):
        threading.Thread.init(self)
        self.id = id
        self.queue = aFiFo
        self.setDaemon(True)
        
    def run(self):
        for i in range(5):
            self.queue.put("[%i] %i" % (self.id, i), True)
            time.sleep(1)

def main():
    
    queue = Queue.Queue()
    thread1 = MyThread(1, queue)
    thread2 = MyThread(2, queue)
    thread1.start()
    thread2.start()
    print "Startn"
    while True:      # the break condition is irresponsible
        try:
            print queue.get(True, 1)
        except Queue.Empty:
            break
        time.sleep(1)
    print "Completed"
    
main()

#--------------------

I don't have that vigor / reserve power now though I may have to write it a little more in detail. 
At any rate, I could probably get a solution.  

Thank you.


bagginsbill ( ) posted Thu, 03 November 2011 at 7:22 AM

There you go - that is very close.

If, in the future, you would like to send things other than strings to the queue, then just do so. In the consumer thread, you can examine the objects sent to see if they are strings or something more complicated. In this way, the worker threads can deliver more than just messages. They can deliver completed work to the main thread.


Renderosity forum reply notifications are wonky. If I read a follow-up in a thread, but I don't myself reply, then notifications no longer happen AT ALL on that thread. So if I seem to be ignoring a question, that's why. (Updated September 23, 2019)


JTrout ( ) posted Thu, 03 November 2011 at 9:01 AM

A so-called queuing model itself is easy to understand.
Therefore, I think that "the program that only main thread calls API of wx" is the most reliable.
However, won't the event hand ring mechanism of wx have a more convenient structure?

I am expecting that it is combination with the event hand ring model of wx that I seem probably to have difficulty.
Or, it may be actually easy. 
Though the superficial use of wx is easy, I may not have understood the event hand ring mechanism of this API yet. An AUI manager, too. 
I try after I rest a little.

Thank you.

By the way, Isn't the stub package of Poser released by anyone?
Though I like Eclipse and PyDev, I don't know how to import a poser package outside of Poser.
If that is possible (probably impossible), it is the most desirable.
Only so long as it is necessary, I am making the stub package of Poser unwillingly gradually.
I should use that stub if perfect stub has been already released by someone.


bagginsbill ( ) posted Thu, 03 November 2011 at 9:23 AM

You are correct - you could use wx event handling. The reason I tend not to use such things is they have a lot of bookkeeping. You have to:

Get an unique event ID

Create a class to represent the event

Bind a listener callback for the event.

...

Remember to later unbind a listener callback for the event.

Furthermore, the whole thing goes through one queue, so if you have several independent activities, they all funnel through the main event handler and you have to sort out who is doing what to whom. I prefer a dedicated queue for each group of master/slave components. But this is a simple matter either way.

I am not aware of a stub poser module.

 


Renderosity forum reply notifications are wonky. If I read a follow-up in a thread, but I don't myself reply, then notifications no longer happen AT ALL on that thread. So if I seem to be ignoring a question, that's why. (Updated September 23, 2019)


JTrout ( ) posted Sun, 06 November 2011 at 8:47 AM

Hi, again

I can't get the expected behavior of callback in Poser.
It seems the event can't get the chance when it is handled.
The following sample code doesn't do an expected behavior with poser.  
The program which has the same event structure do an expected behavior without poser.

What do I mistake?

#-------------------------------------------------------------

-- coding: utf-8 --

import poser
import wx, wx.aui, wx.lib.newevent
import threading, time

(UpdateButtonEvent, EVT_UPDATE_BUTTON) = wx.lib.newevent.NewEvent()
(UpdateCountEvent, EVT_UPDATE_COUNT) = wx.lib.newevent.NewEvent()

class UserEvaluationView(wx.Panel):
    def init(self, model, *args, *kwds):
        super(UserEvaluationView, self).init(args, kwds)
        self.countLabel = wx.StaticText(id=wx.ID_ANY,parent=self, label='', name='count', size = (100,30), style=0)
        self.startButton = wx.Button(self, wx.ID_ANY,"Start", size=(45,20))
        self.startButton.Bind(wx.EVT_BUTTON, self.OnStart)
        self.abortButton = wx.Button(self, wx.ID_ANY,"Abort", size=(45,20))
        self.abortButton.Bind(wx.EVT_BUTTON, self.OnAbort)
        self.abortButton.Disable()
        vLayout1 = wx.BoxSizer(wx.VERTICAL)
        vLayout1.Add(self.countLabel, flag=wx.ALIGN_LEFT|wx.ALL, border=5)
        vLayout1.Add(self.startButton, flag=wx.ALIGN_LEFT|wx.ALL, border=5)
        vLayout1.Add(self.abortButton, flag=wx.ALIGN_LEFT|wx.ALL, border=5)
        self.SetSizerAndFit(vLayout1)
**        self.Bind(EVT_UPDATE_BUTTON, self.OnUpdateButton)

**        self.Bind(EVT_UPDATE_COUNT, self.OnUpdateCount)

        self.thread = None

    def OnStart(self, event):
        if self.thread == None:
            self.thread = TestThread(self)
            self.thread.start()
        
    def OnAbort(self, event):
        if self.thread != None:
            self.thread.abort()
        
    def setForRunning(self):
        self.startButton.Disable()
        self.abortButton.Enable()
        
    def setForStop(self):
        self.startButton.Enable()
        self.abortButton.Disable()
        
    def OnUpdateButton(self, event):
        if event.name == "start":
            self.setForRunning()
        elif event.name== "stop":
            self.setForStop()
        self.Refresh()
        
    def OnUpdateCount(self, event):
        self.countLabel.SetLabel('%3i' % event.count)

class TestThread(threading.Thread):
    def init(self, aView):
        threading.Thread.init(self)
        self.view = aView
        self.setDaemon(True)
        self.abortInvoked = False
        
    def run(self):
**        event = UpdateButtonEvent(name="start")**
**        wx.PostEvent(self.view, event) **
        for i in range(20): # for safety
            if self.abortInvoked:
                break
**            event = UpdateCountEvent(count=i)**
**            wx.PostEvent(self.view, event)**
            # Actually, various processing is put here.
            time.sleep(1) # TBD
**        event = UpdateButtonEvent(name="stop")**
**        wx.PostEvent(self.view, event)**
        self.view.thread = None
            
    def abort(self):
        self.abortInvoked=True

def main():
    model = None # dummy
    man = poser.WxAuiManager()
    root = man.GetManagedWindow()
    panel = UserEvaluationView(model, parent=root)
    pinfo = wx.aui.AuiPaneInfo()pinfo.CloseButton(True).DestroyOnClose(True).Resizable().Float().FloatingSize(wx.Size(200, 200)).BestSize(wx.Size(200, 200))
    man.AddPane(panel, pinfo)
    pinfo.Show()
    man.Update()

main()

#-------------------------------------------------------------


Privacy Notice

This site uses cookies to deliver the best experience. Our own cookies make user accounts and other features possible. Third-party cookies are used to display relevant ads and to analyze how Renderosity is used. By using our site, you acknowledge that you have read and understood our Terms of Service, including our Cookie Policy and our Privacy Policy.