Frage

Also ich bin um mit stackless Python liebäugelt, schreiben eine sehr einfach Webserver selbst zu lehren Programmierung mit Microthreads / Tasklets. Aber nun zu meinem Problem, wenn ich so etwas wie ab -n 100000 -c 50 http://192.168.0.192/ (100k Anfragen, 50 Gleichzeitigkeit) laufen in Apache Bank bekomme ich so etwas wie 6k req / s, das zweite Mal, dass ich es betreibe ich 5.5k bekommen, drittes Mal 5k, vierte Mal, 4.5 k usw. den ganzen Weg hinunter zu 100req / s oder so etwas.

Das Problem geht weg, wenn ich den Python-Skript neu starten, though.

Nun meine Frage ist, warum? Bin ich vergessen Tasklets löschen? Ich habe die stackless.getruncount geprüft () (und es scheint immer 1 zurück, aus irgendeinem Grund), so dass es scheint nicht, wie es tot Tasklets um hängen würde? Ich habe versucht Aufruf .kill () auf allen Tasklets, die getan werden, helfen nicht. Ich kann einfach nicht verstehen diese heraus.

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()
War es hilfreich?

Lösung

Zwei Dinge.

Als erstes bitte Klassenname mit einem Großbuchstaben beginnen machen. Es ist mehr konventionelle und leichter zu lesen.

Noch wichtiger ist, in der stackless_accept Funktion akkumulieren Sie eine list von Sock Objekten, genannt sockets. Diese Liste erscheint endlos zu wachsen. Ja, Sie haben eine remove, aber es ist nicht immer aufgerufen. Wenn der Socket einen Fehler bekommt, dann scheint es, dass es für immer in der Sammlung links wird.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top