Overriding 'select'

David Allen s2mdalle at titan.vcu.edu
Sat Jun 17 23:37:34 EDT 2000


Hello,

I'm relatively new to python, and I've come up with a solution to
one of my problems that is not exactly optimal.  I was hoping to 
solicit advice on what might be better or 'prettier'.

The problem is this.  I've got a Connection object.  Each instance
of a Connection object has a field that is a socket.  The server
that uses these Connection objects wants to call select() on 
Connection objects, not their corresponding sockets.  This is
because the Connection object providesa bunch of methods 
specific to each connection, and holds a lot of data for the
server.  

But when implementing select() inside the Connection object,
I come across the problem - how to use the select() call from
the select module on the socket of the Connection, and then
match it up with the right object later on?

I first wanted to use circular references which didn't work
since sockets seem to be read only.  Say I had an instance
foobar with foobar.sock being a socket object.  I thought
I could do:

foobar.socket._circular_reference = foobar

so that when the sockets came out the other end of select()
I could just check that field for their corresponding object, but
that didn't work.  So I ended up writing this:

(the obj.socket() method returns the socket field from that object)

    def select(self, readers, writers, errors, timeout=0):
        # Do this with hashes instead of circular pointers.
        # make a hash of all the socket objects which hash
        # to their corresponding parents
        # when select returns, grab the hash values
        refhash = {}

        reader_sockets = []
        writer_sockets = []
        errors_sockets = []
    
        for r in readers:
            sock = r.socket()
            # The socket's value in the dictionary is the
            # object the socket belongs to for backreferencing.
            refhash[sock] = r
            if sock:
                reader_sockets.append(sock)
        for w in writers:
            sock = w.socket()
            refhash[sock] = w
            if sock:
                writer_sockets.append(sock)
        for e in errors:            sock = e.socket()
            refhash[sock] = e
            if sock:
                errors_sockets.append(sock)

        r, w, e = select.select(reader_sockets, writer_sockets,
                                errors_sockets, 10)

        rreturn = []
        wreturn = []
        ereturn = []

        # Find out which object each socket belongs to

        for x in r:
            rreturn.append(refhash[x])
        for x in w:
            wreturn.append(refhash[x])
        for x in e:
            ereturn.append(refhash[x])

        return rreturn, wreturn, ereturn


This isn't TOO bad...but it's ugly, and not as fast as
circular references might have been.  Creating a 
dictionary isn't too bad, but when you have 100 clients,
and this needs to be called a whole lot, it's an unneeded
penalty on CPU and memory to have to create a huge
dictionary every time select gets called (and then destroy
it)

Any ideas on speeding this up, or rewriting in a better
way?  Is there any way to get around the read-only problem
on sockets?

-- 
David Allen
http://opop.nols.com/
----------------------------------------
Have you noticed the way people's intelligence capabilities decline 
sharply the minute they start waving guns around? 
- Dr. Who 




More information about the Python-list mailing list