本地的Python HTTP服务器很慢

21 投票
3 回答
25469 浏览
提问于 2025-04-15 21:29

我在创建一个非常简单的Python HTTP服务器时遇到了一些性能问题。主要的问题是,性能会根据我使用的客户端不同而有所变化,而服务器和所有客户端都是在本地机器上运行的。例如,从一个Python脚本发出的GET请求(urllib2.urlopen('http://localhost/').read())需要花费超过一秒钟才能完成,这在服务器没有负载的情况下看起来有点慢。而从Excel使用MSXML2.ServerXMLHTTP发出的GET请求也感觉很慢。不过,从Google Chrome或者使用R的curl插件RCurl请求数据时,响应几乎是瞬间的,这正是我所期待的。

让我更困惑的是,当我在工作电脑上时,任何客户端都没有遇到性能问题(性能问题出现在我家里的电脑上)。这两台电脑都运行Python 2.6,不过工作电脑是Windows XP,而不是7。

下面是我非常简单的服务器示例,它对于任何GET请求都会返回“Hello world”。

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer

class MyHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        print("Just received a GET request")
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()

        self.wfile.write('Hello world')

        return

    def log_request(self, code=None, size=None):
        print('Request')

    def log_message(self, format, *args):
        print('Message')

if __name__ == "__main__":
    try:
        server = HTTPServer(('localhost', 80), MyHandler)
        print('Started http server')
        server.serve_forever()
    except KeyboardInterrupt:
        print('^C received, shutting down server')
        server.socket.close()

注意,在MyHandler中,我重写了log_request()和log_message()这两个函数。这样做的原因是我看到有人说,这些函数执行的完全合格域名查找可能会导致服务器变慢。不幸的是,把它们设置为只打印一个静态消息并没有解决我的问题。

另外,请注意我在MyHandler的do_GET()例程的第一行放了一个print()语句。慢的情况发生在这个消息打印之前,这意味着后面的内容并没有导致延迟。

3 个回答

-1

localhost换成127.0.0.1可以解决这个问题哦 :)

33

请求处理程序会进行反向名称查找,以便在日志中显示客户端的名称。我的Windows 7系统首先进行了一次DNS查找,但没有成功,接着又进行了两次NetBIOS名称查询,每次都超时了2秒,总共延迟了4秒!!

可以看看这个链接:https://bugs.python.org/issue6085

对我有效的另一个解决办法是,在我的请求处理程序中重写BaseHTTPRequestHandler.address_string(),用一个不进行名称查找的版本。

def address_string(self):
    host, port = self.client_address[:2]
    #return socket.getfqdn(host)
    return host

Philippe

19

这听起来不像是代码的问题。一个很好的方法来排查HTTP服务器的问题,就是用telnet连接到它的80端口。然后你可以输入类似下面的内容:

GET /index.html HTTP/1.1
host: www.blah.com
<enter> <enter>

然后观察服务器的回应。看看用这种方法是否会有延迟。

你可能还想关闭任何防火墙,看看它们是否导致了速度变慢。

试试把127.0.0.1换成localhost。如果这样解决了问题,那就说明可能是FQDN查找导致的。

撰写回答