Skip to content

Instantly share code, notes, and snippets.

@vytas7
Last active August 10, 2024 23:18
Show Gist options
  • Save vytas7/9b96e6133b2430ad915b0f71b18f22db to your computer and use it in GitHub Desktop.
Save vytas7/9b96e6133b2430ad915b0f71b18f22db to your computer and use it in GitHub Desktop.
Testing Falcon with free-threaded CPython 3.13
import http
import logging
# import random
import socketserver
import threading
# import time
import wsgiref.simple_server
import falcon
logging.basicConfig(
format="%(asctime)s [%(levelname)s] %(message)s", level=logging.INFO)
class ContentedResource:
def __init__(self):
self._data = {}
self._lock = threading.Lock()
def on_get(self, req, resp):
with self._lock:
resp.media = self._data.copy()
def on_get_item(self, req, resp, itemid):
with self._lock:
item = self._data.get(itemid)
if item is None:
raise falcon.HTTPNotFound
resp.media = item
def on_put_item(self, req, resp, itemid):
item = req.get_media()
if not item:
raise falcon.HTTPUnprocessableEntity
with self._lock:
self._data[itemid] = item
resp.location = f"{req.path}"
resp.status = http.HTTPStatus.CREATED
class DebugMiddleware:
def process_request(self, req, resp):
# thread = threading.current_thread()
# logging.info(f'{req.method} {req.path} {thread=}')
# time.sleep(random.random())
pass
def create_app():
resource = ContentedResource()
app = falcon.App(middleware=[DebugMiddleware()])
app.add_route("/items", resource)
app.add_route("/items/{itemid}", resource, suffix="item")
return app
class ThreadingWSGIServer(socketserver.ThreadingMixIn,
wsgiref.simple_server.WSGIServer):
pass
with wsgiref.simple_server.make_server(
"", 8000, create_app(), ThreadingWSGIServer) as httpd:
logging.info("Serving on port 8000...")
# Serve until process is killed
httpd.serve_forever()
@vytas7
Copy link
Author

vytas7 commented Aug 10, 2024

Running the free-threaded build of CPython 3.13 with GIL:

  7639 requests in 10.00s, 1.22MB read

(CPU utilization is roughly 1 core.)

Running the free-threaded build of CPython 3.13 without GIL (PYTHON_GIL=0):

  32706 requests in 10.00s, 5.24MB read

(CPU is maxed out. Unlike other tests, this one fluctuates wildly.)

Running vanilla CPython 3.12:

  33607 requests in 10.10s, 5.29MB read

(CPU utilization is roughly 1 core. This test could have also also been slightly faster because it was not run in Docker.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment