[ZODB-Dev] Quick ZODB connection synch question

Tim Peters tim at zope.com
Sun Oct 5 17:07:59 EDT 2003


[Shane Hathaway]
>>> Is this the answer you're looking for, Nicholas?
>>>
>>>   import asyncore
>>>   asyncore.loop()
>>>
>>> If you need to run that in a separate thread:
>>>
>>>   import thread, asyncore
>>>   thread.start_new_thread(asyncore.loop, ())

[Nicholas Henke]
>> Oh. Guess it is that simple. :) How about shutting it down cleanly?

[Shane]
> That part might be more difficult.  If asyncore is running in an
> independent thread, it's not easy to tell it to stop.  One way to deal
> with that is to write your own loop, where the body of the loop calls
> asyncore.poll() with a short timeout and checks a global variable to
> see if it's time to stop.

asyncore makes me queasy <0.5 wink>.  The following illustrates what appears
to be a clean way to shut down asyncore without replacing its internals.
I'm becoming skeptical that it's possible to make it simpler, but am not
sure it's complicated enough for all environments (in particular,
Quitter.ADDR becomes a reserved address).  If you run it, you'll see that it
prints "leaving asyncore loop" right after printing 5, and the main loop
keeps going then.

"""
import asyncore
import threading
import socket

class Quitter(asyncore.dispatcher):
    ADDR = 'localhost', 6666

    def __init__(self):
        # Connect a sender socket to a receiver socket.
        # Let asyncore manage the receiver.
        # When it's time to stop asyncore, call stop().
        # That sends something to the receiver, thus waking
        # up the asyncore loop.  handle_read_event() here
        # then raises asyncore's ExitNow exception.
        # BTW, there's no point to making any of these non-blocking.
        server = socket.socket()
        server.bind(self.ADDR)
        server.listen(1)
        self.sender = socket.socket()
        self.sender.connect(self.ADDR)
        self.receiver = server.accept()[0]
        server.close()
        asyncore.dispatcher.__init__(self, self.receiver)

    def readable(self):
        # This makes sure the asyncore loop always passes something
        # to select, so doesn't just sleep(timeout).
        return 1

    def writable(self):
        return 0

    def handle_read_event(self):
        # This gets called by the asyncore loop after stop() sends
        # something to self via self.sender.
        nonsense = self.recv(1)
        assert nonsense == 'q'
        raise asyncore.ExitNow   # tell asyncore to stop

    def stop(self):
        self.sender.send('q') # send anything non-empty

    def close(self):
        asyncore.dispatcher.close(self)  # closes the receiver socket
        self.sender.close()

class AsyncoreRunner(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.q = Quitter()

    def run(self):
        try:
            try:
                asyncore.loop()
            except asyncore.ExitNow:
                pass
        finally:
            print 'leaving asyncore loop'
            self.q.close()
            asyncore.close_all()

    def stop(self):
        self.q.stop()

ar = AsyncoreRunner()
ar.start()

import time
i = 0
while 1:
    time.sleep(1)
    i += 1
    print i
    if i == 5:
        ar.stop()
"""




More information about the ZODB-Dev mailing list