-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The AsyncIO Server should use Python's 3.7 BufferedProtocol when possible ? #1873
Comments
Did you check if Do notice that future development of Sanic is planned based on the I'd love to see a PR with benchmarks, against the streaming branch. |
@tzickel any interest in pursuing this further? |
Sure on which branch to check ?
|
אפשר בשלך. You can make a fork of the repo, then branch off |
Hmm... Doesn't seem to matter that much from my testing (unless I did something wrong) :/ diff --git a/sanic/server.py b/sanic/server.py
index 6adf5dd..ffd60fe 100644
--- a/sanic/server.py
+++ b/sanic/server.py
@@ -31,6 +31,10 @@ from sanic.log import access_logger, logger
from sanic.request import EXPECT_HEADER, Request, StreamBuffer
from sanic.response import HTTPResponse
+try:
+ from asyncio import BufferedProtocol as BaseProtocol
+except ImportError:
+ from asyncio import Protocol as BaseProtocol
try:
import uvloop # type: ignore
@@ -82,7 +86,7 @@ class ConnInfo:
self.client_port = addr[1]
-class HttpProtocol(asyncio.Protocol):
+class HttpProtocol(BaseProtocol):
"""
This class provides a basic HTTP implementation of the sanic framework.
"""
@@ -129,6 +133,7 @@ class HttpProtocol(asyncio.Protocol):
"state",
"_unix",
"_body_chunks",
+ "_buffer",
)
def __init__(
@@ -142,6 +147,7 @@ class HttpProtocol(asyncio.Protocol):
unix=None,
**kwargs,
):
+ self._buffer = memoryview(bytearray(64 * 1024))
asyncio.set_event_loop(loop)
self.loop = loop
deprecated_loop = self.loop if sys.version_info < (3, 7) else None
@@ -289,6 +295,12 @@ class HttpProtocol(asyncio.Protocol):
# Parsing
# -------------------------------------------- #
+ def get_buffer(self, sizehint=-1):
+ return self._buffer
+
+ def buffer_updated(self, nbytes):
+ self.data_received(self._buffer[:nbytes])
+
def data_received(self, data):
# Check for the request itself getting too large and exceeding
# memory limits |
Well, I guess it depends on what and how you are testing. If there is one thing I have learned since being a part of Sanic, it is that performance testing on a web framework is not very accurate and highly conditional. |
I did a fairly crude experiment with this. I ran First, the test ran on a very small response payload. A "hello world" type of response. Using But, when I tested it against a payload of about 250KB, there was a significant difference. It jumped from 119K req/s to 127.5K req/s. That leads me to believe that for larger payloads there is a potential performance increase (or at least not a penalty) that this should warrant another look and inclusion into 21.3. |
Unless someone can prove to me this is faster, I am inclined to close this one. |
Not sure how much performance it can add, but might be worth exploring:
https://bugs.python.org/issue32251
It can be done in a backward compatible way with Python 3.6 like this:
https://github.com/huge-success/sanic/blob/bedf68a9b2025618a94cb8044f495a0abd87a134/sanic/server.py#L47
Instead of inheriting asyncio.Protocol, it can be done:
And inside the implementation, it can be written for both Python 3.6 and 3.7+ by defining the 3 methods (where the first 2 use a preallocated buffer):
The text was updated successfully, but these errors were encountered: