0

以下环境下:Apache -> mod_wsgi -> python -> werkzeug

如何控制是否使用 http ckunking 以及块有多大?

跟进:

我担心的是这之间的区别:

response = werkzeug.wrappers.Response()
response.response = very_long_string
return response

和这个:

response = werkzeug.wrappers.Response()
response.response = [ very_long_string ]
return response

在第一种情况下,werkzeug 遍历字符串并一次发送一个字符。我不知道每个字符是否以自己的块发送,但我知道它比字符串作为一个整体发送的第二种情况要慢得多。

这两种情况之间的速度差异是由于分块吗?还是别的什么?

4

1 回答 1

1

通常,wsgi 指定只要应用程序产生响应内容的任何部分,就应该将数据发送到客户端,而不需要缓冲;即,如果你这样做:

CONTENT = "a bit more content\n"

def my_slow_application(environ, start_response):
    start_response("200 OK", [("Content-Type", "text/plain")])
    yield CONTENT
    sleep(1)

值得注意的是,如果没有Content-Length标头,网关(在您的情况下为 apache/mod_wsgi)无法猜测它已找到所有响应内容,并且由于不允许缓冲,它必须使用分块传输编码。

另一方面,考虑:

def my_slowish_application(environ, start_response):
    start_response("200 OK", [("Content-Type", "text/plain"),
                              ("Content-Length", str(len(CONTENT))])
    yield CONTENT
    sleep(1)

由于应用程序指定了内容长度,并且由于第一个yielded 块正是该长度,网关知道不会有更多数据出现;它可以自行决定使用或不使用分块编码。同样地

def my_fast_application(environ, start_response):
    start_response("200 OK", [("Content-Type", "text/plain")])
    return [CONTENT] * 100

一般不会导致分块;响应是一个列表,它具有有限的大小,因此网关知道它具有整个响应。即使没有来自应用程序的显式标头,它也可以使用 找到内容长度sum(map(len, app_iter)),然后以网络允许的最快速度发送响应。


至于控制块有多“大”,如果客户端连接被阻塞,网关可能会缓冲块;你的应用可能

yield "foo"
sleep(1)
yield "bar"
sleep(1)
yield "baz"

但是如果客户端连接在处理“foo”块时阻塞,网关可能会将 bar 和 baz 缓冲在一起,当连接准备好再次读取时将它们作为单个块发送。简而言之,你无法控制分块,你可能会强制它发生,你可以经常阻止它发生(大多数网关如果没有必要不会分块);但不适合装帧。

于 2014-03-27T15:26:52.620 回答