[Zope-Coders] ThreadedAsync.LoopCallback

Shane Hathaway shane@zope.com
Mon, 24 Feb 2003 14:00:02 -0500


Toby Dickenson wrote:
> Ive just stubled into a new dark corner of zodb; the 
> ThreadedAsync.LoopCallback module. It currently rebinds asyncore.loop to a 
> new function that also provides hooks for callback functions to be triggered 
> before entering a select loop. I am sure I dont fully understand how this is 
> used.
> 
> Previously Zope called asyncore.loop from z2.py to run the main select loop. 
> This was using the ThreadedAsync.LoopCallback version if ZEO is imported.
> 
> In Zope 2.7 this has changed - Zope now has its own main select loop in the 
> Lifetime.py module. It is like asyncore.loop with some additional exit 
> conditions to handle graceful shutdown.
> 
> Does Zope need to be calling the ThreadedAsync.LoopCallback hooks in its loop 
> too?

FWIW, here's my take on ThreadedAsync.  I think we can do away with it, 
getting simpler code in the process, with the only cost being an 
additional thread that runs anytime ZEO client code is used.  Here's an 
informal proposal I sent three weeks ago to an internal list:

"""
I just thought of something that might simplify the current ZEO 
implementation significantly.  Client-side ZEO uses asyncore in an 
unusual way: in order to mix with applications like Zope, it sometimes 
assumes there is no main loop running in another thread, so it runs a 
private loop inline.  This strategy is hard to explain and maintain, and 
it's spread over many parts of the code (as I recall).

What if, instead of relying on the application's main loop, ZEO clients 
ran a private asyncore loop in a ZEO-specific thread?  The client ZEO 
code would need only one such thread per process.  All communication 
with ZEO servers would be channeled through this thread (whereas today 
all server communication goes through the application's main loop). Here 
are some differences.

ThreadedAsync: no longer necessary.  Since the communication loop is 
always running, ZEO clients won't have to switch between asynchronous 
and synchronous mode.

Triggers: ZEO will only need one global trigger.  It will be set up when 
the communication loop is set up.

Interaction with asyncore: We'll have to use an alternate socket map. 
This is a rarely-used feature of asyncore, but it should be safe. 
Alternate socket maps allow different subsystems in an application to 
use asyncore without bumping into each other.  The downside is that all 
calls to set_socket(), add_channel(), and del_channel() need to specify 
the alternate socket map.

In retrospect, I think alternate socket maps running in secondary 
threads may be what Sam Rushing had in mind for problems like this. We 
need asynchronous communication, but it's hard to reuse the 
application's main loop.  So maybe we should use a private communication 
loop.  I've said that Twisted's core might improve the maintainability 
of ZEO, but this solution might achieve the same kind of improvement.
"""

I don't think it would be hard to implement at all.  We'd delete more 
code than we add.  No one is assigned to do it, though.

Shane