[Twisted-Python] Re: GUI responsiveness

I've been following this discussion with some interest because I'm starting a new project that will be heavily centered around both MySQL-based persistency and a graphically demanding GUI. I took a look at wxPython but was somewhat turned off by the complication of integrating it with Twisted, which I'm using to do top-level dispatching of time-consuming stuff in threads and in separate processes, and to perform networking when that functionality inevitably winds up getting added to the application. I had been thinking about PyQT but was turned off by the licensing complications under Windows. However, QT4 is dual-licensed and there is already a conveniently installable GPL version of PyQT for Windows now. (Apparently, someone went to the trouble of recompiling the GPL'd QT3 source under cygwin, and the result seems to work fine for me.) You can get it at http://www.quadgames.com/download/pythonqt/PyQtGPL10.exe. So, I think the choice will be PyQT for me. Comments welcome, though. - Ed Suominen

On 9/14/05, Ed Suominen <general@eepatents.com> wrote:
I've already commented about this on the thread this one spinned off from, but I'll repeat it here: wxPython *can* be used with Twisted, and it's not very complicated. I use two separate threads (with two event loops) and two proxy objects to vehicle the requests from one thread to the other. I just learnt there is a wonderful threadedselectreactor that allows for an easy integration of twisted and wx inside the same event loop, but I haven't tried it yet. Actually, and I'm sure I will say some nonsense here, so please correct me if you are in the know, I'm wondering if having the same loop process both wx and twisted events could harm twisted responsiveness, or viceversa. By the way, I have to say that using proxy objects is not that bad. I actually think it's quite nice to have all the possible interaction formalized as methods all belonging to the same object. But in my case I don't have a *very* complicated interaction: from the network side, I just need to raise dialogs, update the status bar, update table contents, open and close windows and stuff like this. From the gui side I need to start a connection protocol, stop it, trigger communication with a server, send updates, and stuff like this. So, it's not a million of methods, it's just a few, that I actually like having all sorted in the same place. cheers, stefano

Bob Ippolito wrote:
Hmmm. Perhaps I glanced over threadedselectreactor too quickly, since all the discussion seemed to be about wxPython (which I'm not using). However, casting about through the archives, I haven't really found a good description of threadedselectreactor... What's it actually do? Just allow you to integrate 2 loops in a slightly nicer fashion? I integrated my pygame+pyui loop with twisted's default reactor using 5 simple lines of code, so I'm not seeing much room for gain there... Does threadedselectreactor do more, like address GUI responsiveness? Or more to the point, is there a concise overview somewhere? -Jasper

On Sep 14, 2005, at 5:15 PM, Jasper wrote:
http://bob.pythonmac.org/archives/2005/04/17/twisted-and-foreign- event-loops/ http://svn.twistedmatrix.com/cvs/trunk/doc/core/examples/threadedselect/ -bob

Bob Ippolito wrote:
Heh, I'd seen both of those... Neither really suggest any reason to use threadedselectreactor beyond being able to integrate foreign loops. I guess I'm just not seeing what's so great about threadedselectreactor, except perhaps that it's better than wxreactor. -Jasper

On Sep 14, 2005, at 7:35 PM, Jasper wrote:
That's all the reason you need. If you're integrating with a foreign event loop, you either use a custom specific reactor (most of which are broken and/or unmaintained), or you use threadedselectreactor. Writing your own custom specific reactor is almost certainly going to be broken in some way, and it's more complex code that you have to maintain.
I guess I'm just not seeing what's so great about threadedselectreactor, except perhaps that it's better than wxreactor.
It's better than writing your own reactor for every foreign event loop you're interested in, and it's generic enough to integrate with ANYTHING that has a thread-safe way to send a message to the main runloop (basically, all of them can do that). Your pygame+pyui loop is probably less responsive to either network or user events, or perhaps instead chews more CPU than a threadedselectreactor alternative. Fortunately, there's even an example that demonstrates how you could use it in conjunction with pygame. -bob

Nicola Larosa wrote:
Here's what it roughly is, stripping out code and params not directly involved. I just took the simplest thing I could think of, and since it worked I didn't look much further. Perhaps this would have trouble if had frequent network traffic, but I don't. -Jasper class PyuiClient( NetworkClient ): def __init__( self ): # ... self._pyuiRefresh( .001 ) def _pyuiRefresh( self, delay ): pyui.draw() pyui.update() reactor.callLater( delay, self._pyuiRefresh, delay )

Antoine Pitrou wrote:
It's not a busy wait loop, whenever it's not doing anything control is relinquished to twisted. The .001 second delay /is/ really short, and I had originally expected something closer to the screen refresh rate like .01, but after testing I found that .001 performed better. To be honest I don't fully understand why this is the case, as it seems like this would be wastefull, but it works fast enough I can't really justify the time it would take to profile it and figure out exactly what's going on. Anyway, I get 60 FPS, idling CPU use is 5%, and I develop on an older laptop. Since this is a game I don't much care if it slows down other apps, which it does a little. I have no doubt that it could be more efficient, but considering I don't have any speed problems I'm perfectly happy trading this off for code simplicity. -Jasper

On 9/14/05, Ed Suominen <general@eepatents.com> wrote:
I've already commented about this on the thread this one spinned off from, but I'll repeat it here: wxPython *can* be used with Twisted, and it's not very complicated. I use two separate threads (with two event loops) and two proxy objects to vehicle the requests from one thread to the other. I just learnt there is a wonderful threadedselectreactor that allows for an easy integration of twisted and wx inside the same event loop, but I haven't tried it yet. Actually, and I'm sure I will say some nonsense here, so please correct me if you are in the know, I'm wondering if having the same loop process both wx and twisted events could harm twisted responsiveness, or viceversa. By the way, I have to say that using proxy objects is not that bad. I actually think it's quite nice to have all the possible interaction formalized as methods all belonging to the same object. But in my case I don't have a *very* complicated interaction: from the network side, I just need to raise dialogs, update the status bar, update table contents, open and close windows and stuff like this. From the gui side I need to start a connection protocol, stop it, trigger communication with a server, send updates, and stuff like this. So, it's not a million of methods, it's just a few, that I actually like having all sorted in the same place. cheers, stefano

Bob Ippolito wrote:
Hmmm. Perhaps I glanced over threadedselectreactor too quickly, since all the discussion seemed to be about wxPython (which I'm not using). However, casting about through the archives, I haven't really found a good description of threadedselectreactor... What's it actually do? Just allow you to integrate 2 loops in a slightly nicer fashion? I integrated my pygame+pyui loop with twisted's default reactor using 5 simple lines of code, so I'm not seeing much room for gain there... Does threadedselectreactor do more, like address GUI responsiveness? Or more to the point, is there a concise overview somewhere? -Jasper

On Sep 14, 2005, at 5:15 PM, Jasper wrote:
http://bob.pythonmac.org/archives/2005/04/17/twisted-and-foreign- event-loops/ http://svn.twistedmatrix.com/cvs/trunk/doc/core/examples/threadedselect/ -bob

Bob Ippolito wrote:
Heh, I'd seen both of those... Neither really suggest any reason to use threadedselectreactor beyond being able to integrate foreign loops. I guess I'm just not seeing what's so great about threadedselectreactor, except perhaps that it's better than wxreactor. -Jasper

On Sep 14, 2005, at 7:35 PM, Jasper wrote:
That's all the reason you need. If you're integrating with a foreign event loop, you either use a custom specific reactor (most of which are broken and/or unmaintained), or you use threadedselectreactor. Writing your own custom specific reactor is almost certainly going to be broken in some way, and it's more complex code that you have to maintain.
I guess I'm just not seeing what's so great about threadedselectreactor, except perhaps that it's better than wxreactor.
It's better than writing your own reactor for every foreign event loop you're interested in, and it's generic enough to integrate with ANYTHING that has a thread-safe way to send a message to the main runloop (basically, all of them can do that). Your pygame+pyui loop is probably less responsive to either network or user events, or perhaps instead chews more CPU than a threadedselectreactor alternative. Fortunately, there's even an example that demonstrates how you could use it in conjunction with pygame. -bob

Bob Ippolito wrote:
Ok, so it's perhaps more efficient. CPU and user events are fine, although I'm not sure about network response. I imagine the pauses I'm seeing are due to sending large data chunks though, which I don't think threadedselectreactor addresses. -Jasper

Nicola Larosa wrote:
Here's what it roughly is, stripping out code and params not directly involved. I just took the simplest thing I could think of, and since it worked I didn't look much further. Perhaps this would have trouble if had frequent network traffic, but I don't. -Jasper class PyuiClient( NetworkClient ): def __init__( self ): # ... self._pyuiRefresh( .001 ) def _pyuiRefresh( self, delay ): pyui.draw() pyui.update() reactor.callLater( delay, self._pyuiRefresh, delay )

Antoine Pitrou wrote:
It's not a busy wait loop, whenever it's not doing anything control is relinquished to twisted. The .001 second delay /is/ really short, and I had originally expected something closer to the screen refresh rate like .01, but after testing I found that .001 performed better. To be honest I don't fully understand why this is the case, as it seems like this would be wastefull, but it works fast enough I can't really justify the time it would take to profile it and figure out exactly what's going on. Anyway, I get 60 FPS, idling CPU use is 5%, and I develop on an older laptop. Since this is a game I don't much care if it slows down other apps, which it does a little. I have no doubt that it could be more efficient, but considering I don't have any speed problems I'm perfectly happy trading this off for code simplicity. -Jasper
participants (6)
-
Antoine Pitrou
-
Bob Ippolito
-
Ed Suominen
-
Jasper
-
Nicola Larosa
-
Stefano Masini