Python Bottle + Javascript fetch 每秒 10 个请求的瓶颈在哪里?

问题描述 投票:0回答:1

我每秒在 Python Bottle 服务器和使用 JS 的浏览器客户端之间发送 10 个 HTTP 请求:

import bottle, time
app = bottle.Bottle()
@bottle.route('/')
def index():
    return """<script>
var i = 0;
setInterval(() => {
    i += 1;
    let i2 = i;
    console.log("sending request", i2);
    fetch("/data")
        .then((r) => r.text())
        .then((arr) => {
            console.log("finished processing", i2);
        });
}, 100);
</script>"""
@bottle.route('/data')
def data():
    return "abcd"
bottle.run(port=80)

结果很差:

sending request 1
sending request 2
sending request 3
sending request 4
finished processing 1
sending request 5
sending request 6
sending request 7
finished processing 2
sending request 8
sending request 9
sending request 10
finished processing 3
sending request 11
sending request 12

为什么它无法成功处理每秒 10 个请求(在普通 i5 计算机上):我的代码中是否存在已知的瓶颈?

每个请求丢失的 100 毫秒在哪里,导致程序无法保持正常速度,例如:

sending request 1
finished processing 1
sending request 2
finished processing 2
sending request 3
finished processing 3

备注:

  • 用 Flask 而不是 Bottle 进行测试,问题类似

  • 有没有一种简单的方法可以让它工作:

    • 无需 monkey patch Python stdlib(带有

      from gevent import monkey; monkey.patch_all()
      ),

    • 并且无需使用 Gunicorn 或类似的更复杂的设置(在 Windows 上一点也不容易)?

javascript python performance flask bottle
1个回答
1
投票

正如评论中提到的,使用

gevent
使您的代码按预期运行。仅使用 gevent 的猴子补丁功能,无需异步重写:

from gevent import monkey

monkey.patch_all()
import bottle

app = bottle.Bottle()


@bottle.route('/')
def index():
    return """<script>
var i = 0;
setInterval(() => {
    i += 1;
    let i2 = i;
    console.log("sending request", i2);
    fetch("/data")
        .then((r) => r.text())
        .then((arr) => {
            console.log("finished processing", i2);
        });

}, 100);
</script>"""


@bottle.route('/data')
def data():
    return "abcd"


bottle.run(host='0.0.0.0', port=80, server='gevent')

浏览器控制台输出:

sending request 158
(index):10 finished processing 158
(index):6 sending request 159
(index):10 finished processing 159
(index):6 sending request 160
(index):10 finished processing 160
(index):6 sending request 161
(index):10 finished processing 161
(index):6 sending request 162
(index):10 finished processing 162
(index):6 sending request 163
(index):10 finished processing 163
(index):6 sending request 164
(index):10 finished processing 164
(index):6 sending request 165
(index):10 finished processing 165
(index):6 sending request 166

注:

您可以创建自己的线程 WSGI 服务器(如此纯粹的 Python):

import bottle

from wsgiref.simple_server import make_server, WSGIServer
from socketserver import ThreadingMixIn


class ThreadingWSGIServer(ThreadingMixIn, WSGIServer):
    daemon_threads = True


class MyServer:

    def __init__(self, wsgi_app, listen='0.0.0.0', port=80):
        self.wsgi_app = wsgi_app
        self.listen = listen
        self.port = port
        self.server = make_server(self.listen, self.port, self.wsgi_app,
                                  ThreadingWSGIServer)

    def serve_forever(self):
        self.server.serve_forever()


app = bottle.Bottle()


@bottle.route('/')
def index():
    return """<script>
var i = 0;
setInterval(() => {
    i += 1;
    let i2 = i;
    console.log("sending request", i2);
    fetch("/data")
        .then((r) => r.text())
        .then((arr) => {
            console.log("finished processing", i2);
        });

}, 100);
</script>"""


@bottle.route('/data')
def data():
    return "abcd"


if __name__ == '__main__':
    wsgiapp = bottle.default_app()
    myWsgiServer = MyServer(wsgiapp)
    myWsgiServer.serve_forever()
© www.soinside.com 2019 - 2024. All rights reserved.