[Twisted-Python] Usenix paper on event dispatch mechanisms

Moshe Zadka m at moshez.org
Mon Sep 17 14:49:09 MDT 2001


On Mon, 17 Sep 2001, Itamar Shtull-Trauring <lists at itamarst.org> wrote:

> Relevance:
> Doing multiple accept() calls  instead of one (after a select() call 
> tells you a new connection is available) can speed up your application 
> considerably under high loads.

Initial benchmarks show that this is a promising avenue. I got speed-ups
between 10% and 50% depending on the load.

Here is the improved Port class:

>---------- snip ------------<
import fcntl
import FCNTL

class Port(abstract.FileDescriptor):
    """I am a TCP server port, listening for connections.

    When a connection is accepted, I will call my factory's buildProtocol with
    the incoming connection as an argument, according to the specification
    described in twisted.protocols.protocol.Factory.

    If you wish to change the sort of transport that will be used, my
    `transport' attribute will be called with the signature expected for
    Server.__init__, so it can be replaced.
    """

    transport = Server
    sessionno = 0
    unixsocket = None
    interface = ''
    backlog = 5

    def __init__(self, port, factory, backlog=5, interface=''):
        """Initialize with a numeric port to listen on.
        """
        self.port = port
        self.factory = factory
        self.backlog = backlog
        self.interface = interface

    def __repr__(self):
        return "<%s on %s>" % (self.factory.__class__, self.port)

    def createInternetSocket(self):
        """(internal) create an AF_INET socket.
        """
        s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
        fcntl.fcntl(s.fileno(), FCNTL.F_SETFL, os.O_NONBLOCK)
        return s

    def __getstate__(self):
        """(internal) get my state for persistence
        """
        dct = copy.copy(self.__dict__)
        try: del dct['socket']
        except: pass
        try: del dct['fileno']
        except: pass

        return dct

    def startListening(self):
        """Create and bind my socket, and begin listening on it.

        This is called on unserialization, and must be called after creating a
        server to begin listening on the specified port.
        """
        log.msg("%s starting on %s"%(self.factory.__class__, self.port))
        if type(self.port) == types.StringType:
            skt = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
            skt.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            skt.bind(self.port)
            # Make the socket readable and writable to the world.
            mode = os.stat(self.port)[0]
            os.chmod(self.port, mode | stat.S_IROTH | stat.S_IWOTH)
            self.unixsocket = 1
        else:
            skt = self.createInternetSocket()
            skt.bind( (self.interface, self.port) )
        skt.listen(self.backlog)
        self.connected = 1
        self.socket = skt
        self.fileno = self.socket.fileno
        self.startReading()

    def doRead(self):
        """Called when my socket is ready for reading.

        This accepts a connection and callse self.protocol() to handle the
        wire-level protocol.
        """
        try:
            for i in range(40):
                try:
                    skt,addr = self.socket.accept()
                except socket.error, e:
                    if e.args[0] == EWOULDBLOCK:
                        break
                    raise
                protocol = self.factory.buildProtocol(addr)
                s = self.sessionno
                self.sessionno = s+1
                transport = self.transport(skt, protocol, addr, self, s)
                protocol.makeConnection(transport, self)
        except:
            traceback.print_exc(file=log.logfile)

    def doWrite(self):
        """Raises an AssertionError.
        """
        assert 0, "doWrite called on a %s" % str(self.__class__)

    def loseConnection(self):
        """ Stop accepting connections on this port.

        This will shut down my socket and call self.connectionLost().
        """
        # Since ports can't, by definition, write any data, we can just close
        # instantly (no need for the more complex stuff for selectables which
        # write)
        self.stopReading()
        self.connectionLost()

    def connectionLost(self):
        """Cleans up my socket.
        """
        log.msg('(Port %s Closed)' % self.port)
        abstract.FileDescriptor.connectionLost(self)
        self.connected = 0
        self.socket.close()
        if self.unixsocket:
            os.unlink(self.port)
        del self.socket
        del self.fileno

    def logPrefix(self):
        """Returns the name of my class, to prefix log entries with.
        """
        return str(self.factory.__class__)

>------------ snip ----------------<

-- 
The Official Moshe Zadka FAQ: http://moshez.geek
The Official Moshe Zadka FAQ For Dummies: http://moshez.org
Read the FAQ





More information about the Twisted-Python mailing list