We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Pyruvate, a reasonably fast, non-blocking, multithreaded WSGI server

00:00

Formal Metadata

Title
Pyruvate, a reasonably fast, non-blocking, multithreaded WSGI server
Title of Series
Number of Parts
72
Author
Contributors
License
CC Attribution 3.0 Germany:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Identifiers
Publisher
Release Date
Language
Production Year2020

Content Metadata

Subject Area
Genre
Abstract
Pyruvate is a non-blocking, multithreaded WSGI server with competitive performance, implemented in Rust. It features non-blocking read/write based on mio, a rust-cpython based Python interface and a worker pool based on threadpool. The sendfile system call is used for efficient file transfer. Pyruvate integrates with the Python logging API using asynchronous logging. PasteDeploy configuration and systemd socket activation are supported.Beta releases are available for CPython (from 3.6) and Linux. The talk will present the current state of the project and show how to use Pyruvate with Zope/Plone and other Python web frameworks. Another focus will be on the roadmap towards a 1.0 release scheduled for end of this year.
Thread (computing)Server (computing)Plane (geometry)Axiom of choiceDefault (computer science)Computer configurationWrapper (data mining)Thread (computing)Electronic mailing listLimit (category theory)CASE <Informatik>Connectivity (graph theory)Point (geometry)Endliche ModelltheorieUser interfaceExpected valueSoftwareLatent heatBitSoftware developerParameter (computer programming)Different (Kate Ryan album)PlastikkarteHigh-level programming languageRun time (program lifecycle phase)Device driverBijectionAxiom of choiceLevel (video gaming)Server (computing)ImplementationLibrary (computing)MehrprozessorsystemDefault (computer science)Computer configurationCartesian coordinate systemKey (cryptography)Integrated development environmentComputer fileProjective planeConnected spaceWrapper (data mining)DatabaseSingle-precision floating-point formatInterface (computing)Web 2.0Electronic signatureMessage passingSystem callPauli exclusion principleGateway (telecommunications)Client (computing)Cache (computing)Slide ruleDependent and independent variablesEmailSet (mathematics)IterationModule (mathematics)WordMusical ensembleTwin primeUniverse (mathematics)Computer animation
Hand fanHill differential equationZoom lensMemory managementUniqueness quantificationRule of inferenceControl flowImplementationDefault (computer science)Drop (liquid)Variable (mathematics)SpeicherbereinigungAssociative propertyCore dumpLeakRead-only memoryInterface (computing)Pattern matchingCompilerMessage passingPerspective (visual)Module (mathematics)Plane (geometry)Instance (computer science)Server (computing)Data structureSource codeExtension (kinesiology)Computer scienceHigh-level programming languageCore dumpSystem programmingProgramming languageStapeldateiBit rateProjective planeSet (mathematics)Multiplication signResultantLatent heatLibrary (computing)Object (grammar)HTTP cookieTemplate (C++)Modal logicSocial classInterface (computing)Socket-SchnittstelleComputer configurationBitEquivalence relationSheaf (mathematics)Point (geometry)Compilation albumSpeicherbereinigungPattern matchingMemory managementCorrespondence (mathematics)NumberSemiconductor memoryInstance (computer science)Extension (kinesiology)Module (mathematics)Graph (mathematics)Online helpError messageType theoryLeakStudent's t-testSoftwareRun time (program lifecycle phase)Perspective (visual)Device driverSlide ruleCompilerPlastikkarteMessage passingCartesian coordinate systemFunctional (mathematics)Default (computer science)Computer filePerfect groupSource codeSubject indexingData structureGoodness of fitLevel (video gaming)Revision controlRule of inferenceCountingDrop (liquid)Principle of maximum entropyImplementationMacro (computer science)Uniqueness quantificationFormal languagePiWrapper (data mining)Network topologyMereologyServer (computing)HypothesisTask (computing)Computer animation
Data structureSource codePhysical systemExtension (kinesiology)Modul <Datentyp>Execution unitSoftware testingDisintegrationBinary fileError messageRevision controlSocket-SchnittstelleTime domainInterface (computing)Message passingConfiguration spaceMathematical analysisCodeFluid staticsRead-only memoryResource allocationCodeLibrary (computing)Sinc functionUnit testingCovering spaceMultiplication signSoftware testingRevision controlFile formatProjective planeINTEGRALCompilerComputing platformForm (programming)Error messageTraffic reportingMemory managementComputer fileInterface (computing)Different (Kate Ryan album)System callMessage passingChainDomain nameLink (knot theory)Default (computer science)Thread (computing)Socket-SchnittstelleInstallation artInstance (computer science)NumberPhysical systemExecution unitPrincipal ideal domainModule (mathematics)CASE <Informatik>Mathematical analysisRight angleMereologyFluid staticsReading (process)LoginCuboidPoint (geometry)Server (computing)Level (video gaming)Configuration spaceStandard deviationFunctional (mathematics)Wrapper (data mining)Binary codeBuildingPauli exclusion principleOnline chatJSONXML
Mathematical analysisCodeFluid staticsSocket-SchnittstelleRead-only memoryResource allocationGraph (mathematics)Software testingLink (knot theory)Interpreter (computing)Event horizonThread (computing)AbstractionInstance (computer science)IterationDependent and independent variablesLoop (music)Electric currentLimit (category theory)BefehlsprozessorColor managementSimultaneous localization and mappingData storage deviceInheritance (object-oriented programming)Bellman equationConvex hullPointer (computer programming)Time zoneFirewall (computing)CompilerProxy serverPlane (geometry)WebsiteStructural loadMusical ensembleFunctional (mathematics)System callDependent and independent variablesWeb pageError messageDifferent (Kate Ryan album)Loop (music)Uniform resource locatorInstance (computer science)Connected spaceEvent horizonCartesian coordinate systemModal logicRight angleInterpreter (computing)Block (periodic table)Computer configurationLoginCASE <Informatik>ResultantServer (computing)Software testingOperating systemThread (computing)CodeBuffer solutionVacuumGrass (card game)AbstractionMultiplication signCuboidSocket-SchnittstelleLaptopWebsiteLimit (category theory)BefehlsprozessorDatabaseComputer fileNumberDemo (music)Bit rateCombinational logicBitWeb browserVideo game consoleMenu (computing)WritingPhysical systemLenovo GroupComputer animation
User profileFiber bundleConvex hullSurjective functionMenu (computing)Maxima and minimaComputer wormInformationAnnulus (mathematics)Content management systemOpen setPlane (geometry)System administratorLine (geometry)Interior (topology)Zoom lensComputer programmingRange (statistics)Programming languageMusical ensembleMultiplication signProbability density functionSource codeXMLComputer animation
Mobile appCommon Language InfrastructureMaizeCodeFormal languageComputer programmingDomain nameVariety (linguistics)Mach's principleConcurrency (computer science)Drag (physics)Read-only memoryTerm (mathematics)Crash (computing)Vulnerability (computing)Control flowComputer programRepresentation (politics)Memory managementSystem programmingClassical physicsPlane (geometry)SchwerpunktsystemInformationCache (computing)NumberObject (grammar)DatabaseTotal S.A.Data managementMenu (computing)WebsiteError messageMaß <Mathematik>DatabaseMusical ensembleConnected spaceMoment (mathematics)Cartesian coordinate systemThread (computing)BitStructural loadSoftware testingMultiplication signClient (computing)Computer animation
Term (mathematics)Rule of inferenceArithmetic meanInformationHost Identity Protocol2 (number)Pairwise comparisonClient (computing)Moment (mathematics)Web pageBitInstance (computer science)Cache (computing)Computer animation
Rule of inferencePhysical lawTotal S.A.Dean numberConcurrency (computer science)19 (number)Binary fileServer (computing)QuicksortNumber2 (number)Correspondence (mathematics)Instance (computer science)Different (Kate Ryan album)Server (computing)Uniform resource locatorDemo (music)ResultantPairwise comparisonComputer animation
Thread (computing)Software testingBinary fileBranch (computer science)FeedbackBranch (computer science)Software testingRevision controlThread (computing)Musical ensembleTraffic reportingMedical imagingSoftware bugMultiplication signBinary codeBitJSONXMLComputer animation
Link (knot theory)Open sourceContent management systemPlane (geometry)FingerprintSimulationWeb 2.0Time zoneLemma (mathematics)Streaming mediaDifferent (Kate Ryan album)Product (business)Musical ensembleProjective planeTrailControl flowLattice (order)WeightExterior algebraSoftware testingWebsiteLink (knot theory)Software developerComputer animation
Transcript: English(auto-generated)
So, hello and welcome to track two of the Plone Conference 2020. Shortly we will have the talk about pyruvate, a reasonable fast non-blocking multi-thread
WYSI-GI server from Thomas Schorr and I will give this to our talker, speaker, sorry.
Hello everybody and thank you very much for having me here today. My name is Thomas Schorr, I'm a freelance software developer from Freiburg in Germany and I'm working with Python since over 15 years. I'm also a contributor to both Plone and Soap but
about 10 months ago I started a Rust project that I want to present in my talk today and the title of the project, the project name is pyruvate and it's a
Python Enhancement Proposal 3333 which is specifying the Python web server gateway interface aka WYSI. The basic message of the PEP is that you can define a Python call level
with a specific signature that will be called by a server software, the WYSI server. Once for each HTTP request this server receives from a client or upstream web server.
And this Python callable, the WYSI application, returns a set of headers along with an iterable response that will be rendered into an HTTP response by the WYSI server and what we can see on this slide is the simplest possible WYSI application and of course it returns a hello
word message in plain text. Instead of a list it could also return some other iterable. Now when we look at the server side then the server invokes the application call level
once for each HTTP request it receives. I've already said that but there is actually many possibilities for handling those requests. The server could be implemented as a single-threaded server, it could spawn a thread for each incoming request, it could use one-to-one
threading or one-to-n aka clean threading for doing that, it could maintain a pool of worker threads and or it could do Python multi-processing using the Python multi-processing module from the standard library and it could do other things. The WYSI server can give hints
on how it's actually handling the request through the environment dictionary. There are some keys related to request handling but whether the application makes use of those
hints is totally up to the application and for example in SOAP I could not find any hints that SOAP is making use of those handling hints. On the other hand, on the application
side we normally don't have that simple hello world application. We often have a need to connect to components that outlive the single request like databases or caches and those database or cache connections might not actually be thread safe and setting them up
might be expensive and all of the above is true for SOAP because wdb connections are not thread safe and they're also quite expensive to set up. So now there's a recipe for disaster when choosing a WYSI server that uses an inappropriate worker model, so one that
does not fit your application and your application connections. As a consequence, although there are quite a lot of WYSI servers around, we have a fairly limited choice for WYSI servers that are actually suitable for SOAP and Bloom. So there's Waitress which is the
default that has a very good overall performance and it's a pure Python implementation. Then there's Bjorn that some of you might have heard of and it's a C implementation. It's quite fast. It's using non-blocking IO and it's single-threaded. Then there's maybe
some new WYSI options that could work with blown and so and yes there are some other options described in the SOAP documentation but that don't have a very good performance. So eventually I wanted more options. So more options please for WYSI servers that are
suitable for using with SOAP and Bloom. So I put up my personal wish list and I wanted a multi-threaded server doing one-to-one threading using a worker pool because that is the threading model that is working with SOAP. I wanted a paste deploy entry point because
I like that on Waitress. It's very cool because it makes WYSI servers a pluggable component that you can exchange easily. I wanted it of course to handle the SOAP blown use case. I have other use cases for WYSI servers as well but I wanted it to handle
SOAP and Bloom. I wanted a non-blocking IO and I wanted a file wrapper supporting send file which is two features that Waitress doesn't support. Of course I wanted it to be
performing well. This is not about creating the fastest WYSI server around but I wanted competitive performance so that it's actually usable. Non-goals of the project are Python 2 because Python 2 is out of support and then another non-goal is currently ASCII, not yet at least. So maybe in a couple of months
it might be an interesting feature and Windows is also a non-goal. I decided to use Rust for the implementation because I was interested in trying Rust for a while
and I had some naive expectations. I expected it to be faster than Python so in runtime performance I expected it to be better than Python and I expected it to be easier to use than C. Let me elaborate a bit on Rust's performance. At the end of 2018 I've seen a talk by Paul
Emmerich from Technical University of Munich and he was comparing network device drivers for specific network card implemented in different high-level programming languages. His argument was
that high-level languages are safer but he also wanted to assess the performance penalties that are coming with runtime safety checks and garbage collection. So computer science students could apply for implementing a user-space network card driver in a specific high-level language and that would be their thesis.
And in the project they benchmark each driver and the chart you can see on this slide is one such benchmark result and what you can actually see is that there is of course the very fast native C implementation and then next it's Rust that is following. So here we can see
a packet rate so batch size and packet rate benchmarking but there is a couple of other benchmarking results and they all look quite the same so Rust's always very much on top of when it comes to performance.
There's one very specific feature of Rust making it both a safe and a fast language and that is called ownership. So Rust has its own unique very unique implementation of memory management and it's basically a set of rules that the compiler checks at compile time
and these there are three rules so each value in Rust has a variable that's called its owner and there can only be one owner at a time and when the owner goes out of scope the value will be dropped and now a drop dropping actually is a trade so a trade being the Rust version of a
interface and there is a default implementation for drop for dropping a value and you can override it. And also you can still control in Rust where your data is stored. It's a systems
programming language so it allows you to do low level tasks and you can control what kind of memory you are using for your data. And how is that relevant for
safety and performance and as an example I want to quickly look at building a Rust extension for Python so it's about interfacing with Python. When we look at Python memory management there's reference counting and garbage collection so whenever you assign an object then you increase
its ref count and internally in the C API there is a macro called pi-inkref that is invoked for increasing the object's memory reference count and these pi-inkref invocations have to match
with pi-decref invocations so decrementing the reference count and garbage collection occurs when an object's ref count goes to zero and if pi-inkref and pi-decref invocations do not match you'll see memory leaks or and eventually coredoms. Now as an example if we look at
well-known Python C extensions that we all use then we have 63 occurrences of pi-inkref in b-trees which is part of the subdb and we have 19 invocations in soap interface and if we compare that to the Rust C Python crate Rust crate that is implementing the Rust C Python
interface then we only have one pi-inkref invocation and the corresponding pi-decref is implemented in the drop trait for the Python object wrapper and as a result it is
very hard to create a mismatch of pi-inkref and pi-decref invocations in when doing a Rust extension so you're very well set up to create memory safe extensions
and it's getting harder to create memory leaks or coredoms. Of course it's still possible to create more references that you actually need and of course you can still create coredoms by for example not fetching Python errors from the from the error stack.
Well other Rust features that are cool include strict typing that is meaning you will find many problems at compile time and pattern matching is really cool Rust documentation is very good and there are very helpful compiler messages
and yeah there's there's a couple of other good stuff about Rust. So let's start having a closer look at pyroovate from a user perspective. So from a user perspective at first it's a package that is available from pi pi from the python packaging
index and so you could do pip install pyroovate and then it's an importable python module so writing your whiskey application you would do import pyroovate then you define your application callable and then there's basically one single function that you can use
from this module it's called serve and you pass in your application you pass in a socket to use and you mandate you have to mandatorily pass in the number of workers that you want.
So now since this is soap and blown most of you will want to use blown recipe soap2 instance with setc buildout and so in your buildout.cfg if you want to use pyroovate instead of the
and then you basically use a specific whiskey in a template and you that you can pass to blown recipe soap2 instance and essentially in this template you have a server section so server colon main and you specify the pyroovate paste deploy entry point you specify the socket and the
number of workers you want to you want to use and that's it let's have a look a bit at the project structure pyroovate is hosted on gitlab i initially created it with cargo new dash dash
slip so cargo new being the equivalent of cookie cutter or op templates and with dash dash slip you will create a rust library so you end up having a shared object file in linux
then there's a src folder containing the rust sources then there's this cargo.toml that's created by cargo new which pulls in all the necessary rust dependencies there's a setup.py
that you have to add yourself when writing a rust extension and you you need to use a package called setup tools underscore rust and you it's very easy when you use it you get a class named rust extension it's very easy to define your rust extension entry points and and main
essential compilation options and then and and it also defines the paste deploy entry point then there's a pyproject.toml file to specify the build system requirements which you would you can look this up in PEP 518 and there's a tests folder which is currently containing mostly
python tests so these are tox tests these are these are yeah i'm using py.test and tox to run the python tests and the unit tests they are in the rust modules so they are in module
unit tests which is one standard of writing unit tests in rust then there is a underscore init underscore underscore py file in the pyrate folder which is actually the the function definition of the paste deploy entry point and you import the file wrapper that you need for
file wrapper feature and yes i'm running a gitlab pipeline for the project with two stages there's testing and there's a build stage for building binary packages
part of the test is linting so i'm doing a rust format which is opinionated code formatting in rust making rust code formatting very simple because you just use rust form and then your code is formatted the way it should look like i'm sorry for that and then there's clippy which
is a rust linter giving you hints on how to improve your code then i'm running the actual unit tests um and i'm creating a coverage report using kcov which is a coverage tool coverage creation tool working for compiled languages and i'm uploading the the coverage to codecuff.io
because at the time when i started that project codecuff.io was the platform that explicitly supported rust coverage and coveralls.io didn't didn't say so at that time
at least then it's running the python integration tests with talks as i said before for all available python versions and finally if all tests pass and i'm building wheels
so binary packages i'm currently building many linux 2010 wheels for python 3.6 through 3.9 and i switched to many linux 2010 after many linux one
after after the stable rust that i'm using to build the wheels stopped supporting the old abi so there was a there was a an error when loading the rust chat libraries since rust version 47 i think and so i switched to many linux 2010
because i did not want did not want to go through compiling my own tool chain in a in a many linux one docker docker container
important thing to note about many links to talk 2010 is that it needs you will need recent pip and setup tool versions to make the package work so pip version greater than 19 so if you see if you're doing a pip install pyruvate and pip refers
as dist over real which you which you will find out when it tries to invoke the rust compiler and then there's no rust in your platform then you need to upgrade to upgrade pip same for setup tools when you're using it with setc build out you need setup tools version crater 42 and yes and what's what's wanted is as for binary
packages mac os i don't have a mac myself so if anybody is interested in sending me a pull request um actually uh there should not be much difference compared to linux maybe the send file
call is is different on on the mac okay so let's let's do a quick run through the features um it's a rusty python based python interface so a rusty python is one of i think three
currently available python interface python interfaces and i found it to be very suitable for this project then i'm doing and then i'm using a crate called rust crate called metal io so mio which is part of a bigger project called tokyo rs and it's providing
non-blocking io and pyruvate is giving you non-blocking read in all cases and then optional optionally blocking or non-blocking right the default is non-blocking right i'm using a worker pool based on thread pool which is another rust crate doing one-to-one
threading uh i said before that i'm having a paste deploy entry point pyruvate is integrating with python logging so i'm doing asynchronous logging which means when pyruvate is creating a log message it doesn't need to hold the global interpreter log and it also means for you that
you can specify the logging configuration for pyruvate in your whiskey.ini if you're using blown and soap or or just any other way that is by specified in the python logging
documentation you can use tcp or unix domain sockets so ipv4 or ipv6 sockets and unix domain sockets and it also supports systemd socket activation that's not easy that's not easy to use use out of the box with soap and blown because
you need the pid the whiskey server pid to to look up the sockets and that's not quite easy to do with us with a blown recipe soap2 instance
um yes i started to look at performance and it and it turned it turned out to be a rabbit hole so performance in as in number of requests and amount of data transferred by per unit of time and i wanted of course to test it and eventually improve it um so my approach was
for static code analysis and refactoring that was very helpful because pyruvate really started as a hello rust project and so i found out for example that memory allocations are pretty expensive which is which everybody might might everybody else might already know
um then i struggled a lot with how to actually induce socket blocking so um on a normal uh on a normal uh linux it's it's not quite easy to to um to to induce
to to see a as a socket that is blocking them right so if i eventually resolve to limiting socket buffer sizes on a vagrant box for testing purposes purposes um then it would be
good to have that uh with uh docker but um i couldn't find a way yet to do that because socket buffer sizes are um basically specified on the hosts um and it would be good to have to to uh to be able to menu manipulate them on on the on the container of course
um i've been looking at flame crafts from perf data perf data is a cool a tool that is collecting um performance data on on linux so it's actually looking at the time that function spent uh on a stack and uh that's that proved very very good it's very good to
a very good way of assessing performance issues uh so for example i found out uh stuff like as i found out that uh the cold two lower is much more expensive than a call to two ascii
uppercase so and i could eventually uh switch that um and i'm doing um i started doing some load testing with uh ch with and ab so apache benchmarking which is a very old uh performance testing tool um ab will always ever fetch one url where uh ch will will download the whole page
so yes it's quite it's quite different approach of uh testing and uh yeah let's
i want to a quick glance at some design considerations that are affecting performance so um first there's the python global interpreter lock so python code can only run when holding the this global interpreter lock it's like it's like a baton in a relay race
so if you have multiple workers they really need to acquire the global interpreter lock in turn and the approach is of course to acquire the global interpreter lock only for application execution and dropping it when doing uh io and there's there's actually
more than one possible way to do this so um yeah i'm not i'm not quite sure yet what is what is the best the best way of doing it um another um another important issue is io event polling so the this miocrate that i mentioned earlier is presenting an abstraction
called poll instance which will do the necessary system calls um and so whenever the accepts a connection uh those it gets it's gets uh this these connections get registered for read
events with a port with such a poll instance in the main thread and so we are doing non-blocking right so uh it could take multiple turns to read the entire request but eventually
we'll pass the completely read requests plus the connection to the worker pool and the free worker will pick up the connection along with the request and it will invoke the whiskey application it will iterate over the whiskey response chunks which will need the global
interpreter lock and now if you if you do if you're doing blocking right you can simply loop until the response is completely written which is easy but in the non-blocking case you can you will you will be able to write until the there is a e would block or e again
error raised by the operating system and i'm resolving to when that happens i register the connection for write events with a per worker poll instance so there is actually not one poll instance but there is two one is for reading for read events in the main thread
and then each worker's got got its own poll instance for write events um they are not very big so this isn't i'd say overly expensive but there could also be other options for doing that
and yeah once i'm um i receive uh e again error uh the the worker drops the global interpreter lock and will stash the response for a later write until it receives a write write writable events from from the per worker poll instance um yes so first performance
um results on my Lenovo x390 and a vagrant box uh so so i'm doing it both on natively on the on the laptop and a vagrant box with two CPUs two gigs of ram and 8k write buffer size limits
which is really small um so it's it's a lot faster than waitress on a hello world whiskey application and it's still faster than waitress when downloading uh slash url so so in this case
looking at the at the test criteria for benchmarking whiskey service from the soap documentation but it's currently slower than on on slash blown that's interesting i'm still
so i i there's definitely more performance testing needed and there's a lot of different situations and still a lot of different combination possible combinations of setting up like number of threads and so on and yes i'm only starting to to assess that
okay um let's um do a little live demo um i've um i've prepared a build out that i've already run which is defining um a a pyrograde
a blown instance using pyrograde uh so there's a co server that's a blown instance using pyrograde and then there's another instance using uh waitress um they are um running on different ports so the pyrate instance is running on 78 78 and waitress is running on 78 79
co server is already running and i'm starting pyrograde um tell it's telling me it's ready um and i've prepared a browser tab for running this and
database is empty so i'm prompted for a new blown website i'm creating a german site because i'm german i'm used to german um yeah looking at the console it's running that i got i get blown
i can browse a bit i can upload a file i'm uploading the rest programming language documentation it's taking some time because
it's it's rather big but eventually it gets uploaded i can download it i could open it
yeah in a pdf reader um let's maybe have a quick look quick look at the cmi so going to the control panel and going to the databases control panel i can see that there's
two database connections at the moment which is corresponding with the two worker threads that define in the build out um when i reload i see that these are always the same two connections because the application the whiskey application gets copied to each worker thread
and then once upon startup the connection will the the sudb connection will be opened and it will be reused all the time um yes that's basically
all there is to see it's it's just it's just blown this is blown five two latest so it should be five two three i've built it on saturday um and what i can do now after browsing a bit is i can do um i can do some load testing like specify it in uh the soap doc i'm doing
it like specified in the in the soap documentation so 100 concurrent concurrent clients accessing so i'm not running it for 100 seconds because that would take too long i'm running it for 30 seconds and uh yes while i'm doing that we could actually already i think i'm going to do
the same thing with uh waitress later on uh just to get a comparison but while i'm doing that we could maybe already have uh questions if there are any no at the moment there are
no questions okay so i'm starting the waitress instance you see we are seeing waiters starting
up and uh to be fair uh sorry that was the wrong wrong page and to be fair i'm going to
browse a bit on the on this page just to warm the caches of course and then i'll do the same thing for the waitress instance so we can get a comparison on
performance which is of course i am i am biased of course and as i said before there's different results for different urls so you you definitely have to do your your own benchmarking if you
want if you want to to to pick a whiskey server so what we can see here is that um hang on where are we so there is 5809 complete requests in 30 seconds
and here we got 8171 so this is i will wait and it's got a couple more completed requests uh none of the none of the service uh had failed requests and uh corresponding with a
bigger number of completed requests there's there's more data that has actually been transferred yes okay so that so much for the demo um yeah that's basically what i wanted to tell you
i'm planning a 1.0 release for end of this year um there's a couple of things that i that i still want to do currently we are on version 0.8.3 on pi pi it's still a better version so it will have bugs but yeah i'm yeah i'd be happy if uh if you want to you want to give
it a try um there's a there's a feature branch on gitlab that needs some work which is implementing keep alive and junk transport and then i want to integrate in the 1.0 release
and as i said before i want mac os support um it's still open and i want to optimize a bit the pipeline for example i'm currently compiling the cake of binary each time i am running uh the coverage reporting because there is no cake of binary package available available for a Debian
buster which is the base image for rust nightly and then i want to fix an issue with the thread id not that is not reported correctly when doing async logging and of course i'm doing more testing and i hope that i can fix a couple more more bugs yeah that's it um thank you very
much for your attention and yes i if you want to give it a try i'd be i'd be happy for for
for feedback for your feedback i'm looking forward to your feedback feedback thank you very much um thank you thomas um there was one question in um in the slido um i guess it's kind of answered um the question was uh is it a
project to keep an eye on or is it ready for production yet um it's better um i'm using it in production on a couple of smaller sites and you can definitely use it for
for development as a drop-in replacement for waitress and i think you also can use it for testing and i i think it's it's it's not a it's not a replacement for waitress it's an alternative
so it's got it's got a couple of features that are the same which are the features that you you need to to make it suitable for use with soap and blow and then you've got a couple of different features like non-blocking io um yeah and um and that makes it makes it
a bit different from from waitress so so you might want to try it in different situations or you might just want to compare it but i think you can start yeah start yeah start i started using it in production okay then thank you from winston for this uh answer and uh thank you
thomas for um the talk um i would um encourage everyone to come to the uh face-to-face you can
find the link down below under the stream just by click on join face to face and yeah we have a break on this track i guess for nearly an hour
um so see you back in an hour hopefully thank you thank you