Pergunta

Então, eu estou brincando ao redor com python stackless, escrever um muito simples servidor para me ensinar programação com microroscas / tasklets. Mas agora para o meu problema, quando eu executar algo como ab -n 100000 -c 50 http://192.168.0.192/ (100k pedidos, 50 de simultaneidade) em apache banco eu recebo algo como 6k req / s, a segunda vez que executá-lo eu recebo 5.5k, terceira vez 5k, quarta vez, 4,5 k, etc. todo o caminho para 100req / s ou algo assim.

O problema desaparece quando eu reiniciar o script python, no entanto.

Agora a minha pergunta é por quê? Eu estou esquecendo-se de excluir tasklets? Eu verifiquei o stackless.getruncount () (e ele sempre parece retornar 1, por algum motivo) para que ele não parece que não haveria nenhum tasklets mortos pendurados em torno de? Eu tentei ligar para .kill () em todas as tasklets que são feitas, não ajuda. Eu simplesmente não consigo descobrir isso.

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()
Foi útil?

Solução

Duas coisas.

Em primeiro lugar, por favor, faça Nome da classe começar com uma letra maiúscula Letter. É mais convencional e mais fácil de ler.

Mais importante, na função stackless_accept você acumular um list de objetos Sock, chamado sockets. Esta lista aparece a crescer indefinidamente. Sim, você tem um remove, mas não é sempre invocado. Se a luva é um erro, então parece que será deixado na coleção para sempre.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top