script - ¿El rendimiento de la red python sin jerarquía se degrada con el tiempo?
python para redes (1)
Dos cosas.
Primero, haga que el nombre de clase comience con una letra mayúscula. Es más convencional y más fácil de leer.
Más importante aún, en la función stackless_accept
, usted acumula una list
de objetos Sock
, llamados sockets
. Esta lista parece crecer infinitamente. Sí, tiene una remove
, pero no siempre se invoca. Si el socket obtiene un error, parece que se dejará en la colección para siempre.
Así que estoy jugando con python sin pilas, escribiendo un servidor web muy simple para enseñarme programación con microthreads / tasklets. Pero ahora a mi problema, cuando ejecuto algo como ab -n 100000 -c 50 http://192.168.0.192/
(100k peticiones, 50 concurrency) en apache bench obtengo algo así como 6k req / s, la segunda vez que corro Obtengo 5.5k, la tercera vez 5k, la cuarta vez, 4.5k, etc. hasta 100req / so algo así.
El problema desaparece cuando reinicio el script de Python.
Ahora mi pregunta es por qué? ¿Me olvido de eliminar los tasklets? He comprobado el stackless.getruncount () (y parece que siempre devuelve 1, por alguna razón) por lo que no parece que haya tareas agotadas. Intenté llamar a .kill () en todas las tareas realizadas, no ayudaba. Simplemente no puedo entender esto.
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()