Stackless Python Netzwerk-Performance erniedrigender im Laufe der Zeit?
-
23-08-2019 - |
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()
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.