o desempenho da rede python Stackless degradar ao longo do tempo?
-
23-08-2019 - |
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()
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.