[PEAK] Anybody using reactors?

Bob Ippolito bob at redivi.com
Tue Jan 13 21:21:53 EST 2004


On Jan 13, 2004, at 9:06 PM, Phillip J. Eby wrote:

> At 08:47 PM 1/13/04 -0500, Bob Ippolito wrote:
>
>> On Jan 13, 2004, at 8:25 PM, Phillip J. Eby wrote:
>>
>>> At 08:01 PM 1/13/04 -0500, Bob Ippolito wrote:
>>>> and it won't integrate very nicely with some GUI frameworks 
>>>> (especially OS X, because iterate basically starts up the runloop 
>>>> and shuts it down with a callLater.. it's only there because the 
>>>> tests use iterate all over the place instead of run/stop).
>>>
>>> That seems a bit more problematic, although it could be worked 
>>> around by additionally creating a running.IMainLoop that used 
>>> reactor.run(), and an events.IScheduler that used reactor.callLater. 
>>>  However, these would all be "non-default" implementations of those 
>>> components as far as PEAK was concerned, and would require more 
>>> [Component Factories] configuration to use.  But they would then be 
>>> compatible with any Twisted reactors.  I'm not sure how much effort 
>>> I want to put into supporting that, since PEAK frameworks are never 
>>> going to depend on Twisted being installed, in order to run.  That 
>>> makes it difficult for them to remain tested in the absence of 
>>> Twisted.
>>>
>>> OTOH, I suppose I could leave IBasicReactor and UntwistedReactor 
>>> around, and use them to test the reactor-driven IScheduler, 
>>> IMainLoop, and ISelector.  But I'd still prefer to phase them out 
>>> for direct use in PEAK itself.  I guess in a4 they could move into 
>>> the test suite, and out of the main code, so you wouldn't be able to 
>>> use a reactor in PEAK 0.5a4 unless you were also using Twisted, or 
>>> were willing to jump through some hoops to use the code stashed away 
>>> in the test suite.
>>
>> I don't know exactly what you mean by all this, but I do know it 
>> won't work with the OS X reactor, because it needs run/stop :)
>
> Um, see the part above where I said "additionally creating a 
> running.IMainLoop that used reactor.run()".  :)

Yeah, I ignored that part because it sounds like too much work for you 
to bother -- sorry.

>
>> I could rewrite it so that it revolved around usage of iterate(), but 
>> the typical use case is that your network application starts *after* 
>> the GUI runloop does, so iterate() wouldn't exactly be compatible 
>> (since the GUI runloop has already started, and you're *in* a 
>> callback from it, you can't really iterate it) which complicates that 
>> significantly.
>> Basically, OS X has its own written-in-C reactor that GUI Python 
>> (well, PyObjC) applications are running in and should yield to *it*, 
>> not vice versa.
>
> And it can't ever be run recursively?  Not that that's an issue if I 
> do the workaround I described above, but it *is* an issue for programs 
> that want control of their top-level loop for whatever reason, e.g. to 
> force events to be processed until something happens in synchronous 
> code.  I realize that in the Twisted world, there's no such thing as 
> synchronous code, but for "application" code IMO it's better to nest 
> asynchrony within synchrony, than to try to turn the entire system 
> inside out to be 100% asynchronous.

You can have as many recursive runloops as you want, the problem is 
that you have to do some evil hacks if you want an embedded runloop to 
pass events back up to its parent runloop.  Here's an example, in 
pyobjc I wrote an example called PyInterpreter.. which basically tries 
to provide an asynchronous Python interpreter to the user.  The problem 
is that Python has useful interpreter features that block on stdin, so 
in order to facilitate readline() and read() on stdin I had to turn 
that inside out.  If I had stackless, it wouldn't be a problem, but I 
didn't.. so it looks like this:

     def _nestedRunLoopReaderUntilEOLchars_(self, eolchars):
         """
         This makes the baby jesus cry.

         I want co-routines.
         """
         app = NSApplication.sharedApplication()
         NSAnyEventMask = 0xFFFFFFFFL
         window = self.textView.window()
         self.setCharacterIndexForInput_(self.lengthOfTextView())
         # change the color.. eh
         self.textView.setTypingAttributes_({
             NSFontAttributeName:self.font(),
             NSForegroundColorAttributeName:self.codeColor(),
         })
         while True:
             event = app.nextEventMatchingMask_untilDate_inMode_dequeue_(
                 NSAnyEventMask,
                 NSDate.distantFuture(),
                 NSDefaultRunLoopMode,
                 True)
             if (event.type() == NSKeyDown) and (event.window() == 
window):
                 eol = event.characters()
                 if eol in eolchars:
                     break
             app.sendEvent_(event)
         cl = self.currentLine()
         if eol == '\r':
             self.writeCode_('\n')
         return cl+eol

I know there's a lot of unfamiliar framework code in there, but 
basically it iterates a nested runloop (nextEventMatchingMask), spys on 
some events, and then dispatches the ones it doesn't digest.  This 
makes Python code get called on *every event*, and that's not really 
good for performance at all.

In any case, I disagree with you on sync wrapping async.. GUI 
applications should as asynchronous as possible.

-bob
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 2357 bytes
Desc: not available
Url : http://www.eby-sarna.com/pipermail/peak/attachments/20040113/68d04925/smime.bin


More information about the PEAK mailing list