Domanda

Così sto giocando intorno con stackless pitone, scrivendo una molto semplice server web per insegnare a me stesso la programmazione con microspire / tasklets. Ma ora al mio problema, quando corro qualcosa come ab -n 100000 -c 50 http://192.168.0.192/ (100k richieste, 50 concorrenza) in panchina apache ho qualcosa come 6k req / s, la seconda volta che l'eseguo ottengo 5.5k, terza volta 5k, quarta volta, 4,5 k, ecc tutta la strada fino a 100req / s o qualcosa del genere.

Il problema va via quando riavvio lo script python, però.

Ora la mia domanda è: perché? Sto dimenticando eliminare tasklets? Ho controllato lo stackless.getruncount () (e sembra sempre di ritornare 1, per qualche motivo) in modo che non sembra come ci sarebbero tasklets morto appeso in giro? Ho provato a chiamare .kill () su tutte le tasklets che sono state svolte, non ha aiutato. Io proprio non riesco a capire questo fuori.

import socket
import select
import stackless
import time

class socket_wrapper(object):
    def __init__(self, sock, sockets):
        super(socket_wrapper, self).__init__()
        self.sock = sock
        self.fileno = sock.fileno
        self.sockets_list = sockets
        self.channel = stackless.channel()
        self.writable = False
        self.error = False

    def remove(self):
        self.sock.close()
        self.sockets_list.remove(self)

    def send(self, data):
        self.sock.send(data)

    def push(self, bytes):
        self.channel.send(self.sock.recv(bytes))

def stackless_accept(accept, handler, recv_size=1024, timeout=0):
    sockets = [accept]

    while True:
        read, write, error = select.select(sockets, sockets, sockets, timeout)

        for sock in read:
            if sock is accept:
                # Accept socket and create wrapper
                sock = socket_wrapper(sock.accept()[0], sockets)

                # Create tasklett for this connection
                tasklet = stackless.tasklet(handler)
                tasklet.setup(sock)

                # Store socket
                sockets.append(sock)

            else:
                # Send data to handler
                sock.push(recv_size)

        # Tag all writable sockets
        for sock in write:
            if sock is not accept:
                sock.writable = True

        # Tag all faulty sockets
        for sock in error:
            if sock is not accept:
                sock.error = True
            else:
                pass # should do something here if the main socket is faulty

        timeout = 0 if socket else 1
        stackless.schedule() 

def simple_handler(tsock):
    data = ""

    while data[-4:] != "\r\n\r\n":
        data += tsock.channel.receive()

    while not tsock.writable and not tsock.error:
        stackless.schedule()

    if not tsock.error:
        tsock.send("HTTP/1.1 200 OK\r\nContent-length: 8\r\n\r\nHi there")
        tsock.remove()

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(("192.168.0.192", 8000))
sock.listen(5)

stackless.tasklet(stackless_accept)(sock, simple_handler)
stackless.run()
È stato utile?

Soluzione

Due cose.

In primo luogo, si prega di fare Nome classe iniziare con una lettera maiuscola. E 'più convenzionale e più facile da leggere.

Ancora più importante, nella funzione stackless_accept si accumulano un list di oggetti Sock, di nome sockets. Questo elenco viene visualizzato a crescere all'infinito. Sì, avete un remove, ma non è sempre invocato. Se la presa ottiene un errore, allora sembra che sarà lasciato nella collezione per sempre.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top