我有一个python脚本是一个http服务器:http://paste2.org/p/89701,当它与ApacheBench(ab)进行基准测试时,其并发级别(-c switch)低于或等于我在中指定的值socket.listen() - 在源代码中调用一切正常,但是只要将并发级别放在apache bench中,就高于socket.listen()中的值 - 调用性能会在地板上掉落,例如:
两次调用之间的代码没有任何变化,我无法弄清楚出了什么问题 - 现在已经有一天出现这个问题了。还要注意:相同代码的多路复用版本(我写的与线程版本进行比较)无论socket设置为什么设置为什么,或者将apache中的并发(-c开关)设置为什么,都可以工作。 / p>
我花了一天时间在IRC / python文档上,发布在comp.lang.python和我的博客上 - 我找不到任何人甚至知道可能出错的地方。帮帮我!
答案 0 :(得分:7)
我无法确认您的结果,并且您的服务器编码为fishy。我掀起了自己的服务器,也没有这个问题。让我们将讨论推向更简单的层面:
import thread, socket, Queue
connections = Queue.Queue()
num_threads = 10
backlog = 10
def request():
while 1:
conn = connections.get()
data = ''
while '\r\n\r\n' not in data:
data += conn.recv(4048)
conn.sendall('HTTP/1.1 200 OK\r\n\r\nHello World')
conn.close()
if __name__ == '__main__':
for _ in range(num_threads):
thread.start_new_thread(request, ())
acceptor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
acceptor.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
acceptor.bind(('', 1234))
acceptor.listen(backlog)
while 1:
conn, addr = acceptor.accept()
connections.put(conn)
在我的机器上:
ab -n 10000 -c 10 http://127.0.0.1:1234/ --> 8695.03 [#/sec]
ab -n 10000 -c 11 http://127.0.0.1:1234/ --> 8529.41 [#/sec]
答案 1 :(得分:4)
为此,我还实现了一个异步版本:
import socket, Queue, select
class Request(object):
def __init__(self, conn):
self.conn = conn
self.fileno = conn.fileno
self.perform = self._perform().next
def _perform(self):
data = self.conn.recv(4048)
while '\r\n\r\n' not in data:
msg = self.conn.recv(4048)
if msg:
data += msg
yield
else:
break
reading.remove(self)
writing.append(self)
data = 'HTTP/1.1 200 OK\r\n\r\nHello World'
while data:
sent = self.conn.send(data)
data = data[sent:]
yield
writing.remove(self)
self.conn.close()
class Acceptor:
def __init__(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', 1234))
sock.listen(10)
self.sock = sock
self.fileno = sock.fileno
def perform(self):
conn, addr = self.sock.accept()
reading.append(Request(conn))
if __name__ == '__main__':
reading = [Acceptor()]
writing = list()
while 1:
readable, writable, error = select.select(reading, writing, [])
for action in readable + writable:
try: action.perform()
except StopIteration: pass
执行:
ab -n 10000 -c 10 http://127.0.0.1:1234/ --> 16822.13 [#/sec]
ab -n 10000 -c 11 http://127.0.0.1:1234/ --> 15704.41 [#/sec]
答案 2 :(得分:0)
我在tomcat / java的积压上找到了this article,它在积压中提供了一个有趣的见解:
例如,如果所有线程都忙 在java处理请求,内核 将处理SYN和TCP握手 直到它的积压已满。当。。。的时候 积压已经满了,它就会掉线 未来的SYN请求。它不会发送 一个RST,即导致“连接被拒绝” 在客户端,而不是客户端 假设包丢失了 重新传输SYN。希望, 积压队列将被清除 然后
正如我所解释的那样,通过要求ab创建更多的同时连接而不是你的 socket配置为处理数据包丢弃,而不是拒绝,我不知道 ab如何处理。可能是它重新发送SYN,但可能在等待之后 一会儿。这可能甚至在某处(TCP协议?)。
如上所述,我不知道,但我希望这暗示了原因。
祝你好运!答案 3 :(得分:0)
看起来你并没有真正获得并发。显然,当你执行socket.accept()时,主线程不会立即返回等待下一个连接。也许你的连接处理线程只是python代码,所以你要通过SIL(单个解释器锁)进行顺序化。
如果线程之间没有繁重的通信,那么最好使用多进程方案(当然还有预先生成的进程池)
答案 4 :(得分:0)
好的,所以我在一个完全不同的服务器上运行代码 - (我在slicehost获得了一个vps),没有一个问题(一切都按预期工作)所以老实说我认为现在我的笔记本电脑出了问题; p
感谢大家的帮助!