mirror of
https://github.com/django/django.git
synced 2025-10-24 14:16:09 +00:00
Fixed #33865 -- Optimized LimitedStream wrapper.
The current implementation of LimitedStream is slow because .read() performs an extra copy into a buffer and .readline() performs two extra copies. The stream being wrapped is already typically a BytesIO object so this is unnecessary. This implementation has largely been untouched for 12 years and, inspired by a simpler implementation in werkzeug, it was possible to achieve the following performance improvement: LimitedStream.read() (single line): Mean +- std dev: [bench_limitedstream-main] 286 ns +- 6 ns -> [bench_limitedstream-patch] 227 ns +- 6 ns: 1.26x faster LimitedStream.readline() (single line): Mean +- std dev: [bench_limitedstream-main] 507 ns +- 11 ns -> [bench_limitedstream-patch] 232 ns +- 8 ns: 2.18x faster LimitedStream.read(8192) (single line): Mean +- std dev: [bench_limitedstream-main] 360 ns +- 8 ns -> [bench_limitedstream-patch] 297 ns +- 6 ns: 1.21x faster LimitedStream.readline(8192) (single line): Mean +- std dev: [bench_limitedstream-main] 602 ns +- 10 ns -> [bench_limitedstream-patch] 305 ns +- 10 ns: 1.98x faster LimitedStream.read() (multiple lines): Mean +- std dev: [bench_limitedstream-main] 290 ns +- 5 ns -> [bench_limitedstream-patch] 236 ns +- 6 ns: 1.23x faster LimitedStream.readline() (multiple lines): Mean +- std dev: [bench_limitedstream-main] 517 ns +- 19 ns -> [bench_limitedstream-patch] 239 ns +- 7 ns: 2.16x faster LimitedStream.read(8192) (multiple lines): Mean +- std dev: [bench_limitedstream-main] 363 ns +- 8 ns -> [bench_limitedstream-patch] 311 ns +- 11 ns: 1.17x faster LimitedStream.readline(8192) (multiple lines): Mean +- std dev: [bench_limitedstream-main] 601 ns +- 12 ns -> [bench_limitedstream-patch] 308 ns +- 7 ns: 1.95x faster Geometric mean: 1.59x faster
This commit is contained in:
committed by
Mariusz Felisiak
parent
57f5669d23
commit
b47f2f5b90
@@ -81,7 +81,7 @@ class WSGIFileWrapperTests(TestCase):
|
||||
|
||||
def test_file_wrapper_uses_sendfile(self):
|
||||
env = {"SERVER_PROTOCOL": "HTTP/1.0"}
|
||||
handler = FileWrapperHandler(None, BytesIO(), BytesIO(), env)
|
||||
handler = FileWrapperHandler(BytesIO(), BytesIO(), BytesIO(), env)
|
||||
handler.run(wsgi_app_file_wrapper)
|
||||
self.assertTrue(handler._used_sendfile)
|
||||
self.assertEqual(handler.stdout.getvalue(), b"")
|
||||
@@ -89,7 +89,7 @@ class WSGIFileWrapperTests(TestCase):
|
||||
|
||||
def test_file_wrapper_no_sendfile(self):
|
||||
env = {"SERVER_PROTOCOL": "HTTP/1.0"}
|
||||
handler = FileWrapperHandler(None, BytesIO(), BytesIO(), env)
|
||||
handler = FileWrapperHandler(BytesIO(), BytesIO(), BytesIO(), env)
|
||||
handler.run(wsgi_app)
|
||||
self.assertFalse(handler._used_sendfile)
|
||||
self.assertEqual(handler.stdout.getvalue().splitlines()[-1], b"Hello World!")
|
||||
@@ -102,7 +102,7 @@ class WSGIFileWrapperTests(TestCase):
|
||||
response when file_wrapper is used.
|
||||
"""
|
||||
env = RequestFactory().get("/fileresponse/").environ
|
||||
handler = FileWrapperHandler(None, BytesIO(), BytesIO(), env)
|
||||
handler = FileWrapperHandler(BytesIO(), BytesIO(), BytesIO(), env)
|
||||
handler.run(get_internal_wsgi_application())
|
||||
# Sendfile is used only when file_wrapper has been used.
|
||||
self.assertTrue(handler._used_sendfile)
|
||||
@@ -119,7 +119,7 @@ class WSGIFileWrapperTests(TestCase):
|
||||
@override_settings(ROOT_URLCONF="builtin_server.urls")
|
||||
def test_file_response_call_request_finished(self):
|
||||
env = RequestFactory().get("/fileresponse/").environ
|
||||
handler = FileWrapperHandler(None, BytesIO(), BytesIO(), env)
|
||||
handler = FileWrapperHandler(BytesIO(), BytesIO(), BytesIO(), env)
|
||||
with mock.MagicMock() as signal_handler:
|
||||
request_finished.connect(signal_handler)
|
||||
handler.run(get_internal_wsgi_application())
|
||||
|
||||
Reference in New Issue
Block a user