13 ms·
Show HN: Socketify.py: Http/Https and WebSockets servers for PyPy3 and Python3
- kasey_junk 4y agoThis is a python wrapper around libuv not a pure python solution (not that it’s bad but it explains the click bait title).
- korijn 4y agoWould a framework like uvicorn/fastapi be able to achieve similar performance if it were backed by libuv (as opposed to e.g. asyncio)?
- cirospaciari 4y agouvicorn and fastapi is backed by libuv :) it uses uvloop
- matsemann 4y agoPydantic is unreasonably slow for big datastructures, though. For simple performance tests with simple requests/response it's probably fast. But with lots of the data marshalling happening in python some things are really slow in real life use cases.
- cirospaciari 4y agoYeah i have a lot of things to do, to minimize this types of things. But Caching Tools that never cross GIL will boost a lot of performance in real life scenarios too. See https://github.com/cirospaciari/socketify.py/issues/60 https://github.com/cirospaciari/socketify.py/issues/60 I plan to create an native Redis cache and memcache too.
- wdroz 4y agopydandic-core [0] will hopefully solve this issue (written in Rust) [0] -- https://github.com/pydantic/pydantic-core https://github.com/pydantic/pydantic-core
- LtWorf 4y agoAuthor of typedload here. Pydantic is indeed really slow (https://ltworf.github.io/typedload/performance.html https://ltworf.github.io/typedload/performance.html) typedload is faster and written in pure python (unlike pydantic). I know they are rewriting it in rust… but I don't know what will come out of it. After all my pure python implementation already manages to beat pydantic's binary, and when unions are in use, also apischema's binary.
- cirospaciari 4y agoI will take a look! pure python will perform great on PyPy!
- no_circuit 4y agoThe perf part of the tests just seems to be a microbenchmark for seeing how fast the various frameworks can parse a 30000x300 dict of strings representing numbers [1]. If that is all one's application does, and can use your library in their organization/team, that's great. However a 2-3x performance boost for the parsing stage for a use case like an API call might not matter when that could be overshadowed by validation and/or upstream API calls. A realistic app would likely use a validation library like Pydantic's [2] to throw a custom typed-error that can be processed, e.g., localization, before returning it downstream. [1] https://github.com/ltworf/typedload/blob/37c72837e0a8fd5f3502182e8d7716f13045e4d7/perftest/load%20big%20dictionary.py#L70 https://github.com/ltworf/typedload/blob/37c72837e0a8fd5f350... [2] https://docs.pydantic.dev/usage/validators/ https://docs.pydantic.dev/usage/validators/
- LtWorf 4y ago> a microbenchmark for seeing how fast the various frameworks can parse a 30000x300 dict of strings representing numbers [1]. Did you somehow miss all the other tests, even thought they are higher on the page? The important test is shown first: loading objects. I'm not trying to benchmark my wifi or my disk. The IO time is not included there on purpose. Of course a bigger application that does other things wouldn't see this huge difference in performance. But I'm testing the performance of a library here. typedload can use validators, but since it doesn't reimplement attrs/dataclass, I had no interest in testing those… it'd be a race between libraries I didn't write. typedload's exceptions contain enough detail to tell the end user what went wrong. when encountering errors in lists, typedload slows down due to keeping compatibility with python 3.7. However in my test with loading objects, despite the slowdown it remains faster than pydantic.
- cirospaciari 4y agouvicorn uses uvloop that is an wrapper to libuv ;) almost any performance focused package use native extensions (CFFI, Cython, HPy, Python CAPI etc)
- Ensorceled 4y agoI don't really understand this criticism nor why it's "clickbait". I have 12 "unpure" python packages in production. If my app ever needs WSGI, I'll have 13.
- ModernMech 4y agoThe reason this is clickbait is because you can wrap libuv in some other language and get the same results. So what’s the purpose of this article? That a language can wrap libuv is not a new or interesting idea.
- pantsforbirds 4y agoWhy do people only get upset about this sort of thing when it comes to web servers? I don't see the same nitpicks when its a BLAS library, or when it uses a CUDA kernel under the hood. Obviously python is a slow language and needs the C implementation to be fast. You could say the same thing for the vast majority of the python code base.
- commitpizza 4y agoNode.js uses libuv also but it is way slower and tbh, can't you compare node to other things because of that it is using v8 and libuv? I don't understand this this logic.
- div72 4y agoProbably should add that it's faster with PyPy as it might not be obvious on how an interpreted language like Python can beat an AOT compiled language like Go. Interesting results nevertheless.
- cirospaciari 4y agoYeah, I'm converting to HPy and it probably will be faster in CPython too, but like you said AOT is hard to beet without JIT at least. But with CPython is faster than Golang Gin :D
- kaba0 4y agoGraal JIT often beats Graal AOT in the Java “universe”.
- cirospaciari 4y agojust wanna see how GraalPython will perform when i finish the HPy version
- pluggnb 4y agoWonder when a techempower benchmark will comeout
- cirospaciari 4y agoYou can see the preliminaries results here https://www.techempower.com/benchmarks/#section=test&runid=124fd2af-3030-4315-8876-e1db1fa91193&test=plaintext&l=hra0hr-35r https://www.techempower.com/benchmarks/#section=test&runid=1...
- rishav_sharan 4y agoWhy do you think the Fortunes results are not that competitive? I would have expected the python pg drivers to be very mature.
- cirospaciari 4y agoasyncio and python async is very slow, that's why i'm planning to build alternatives to it too!
- rishav_sharan 4y agomakes sense. Best of luck to you.
- deleted 4y ago[deleted]
- t8sr 4y agoOthers point out that calling it a Python framework might be disingenuous, but only if your goal is to compare programming languages. If you're a web developer, trying to pick a framework for websockets, you probably don't care that the Python framework is a libuv wrapper, while to Go framework is native. So well done, I guess? I am really happy to see library authors taking performance seriously! EDIT: This is assuming the benchmark is actually fair. I haven't looked at it, but it's not uncommon for benchmarks to be comparing apples and oranges.
- cirospaciari 4y agoPython framework because is an framework for python, like most performance focused frameworks for python, this uses a lot of native code. uvicorn uses uvloop that is an wrapper for libuv. Web developer dont care if the framework is written in native or it is an wrapper, developers just want something that works in a nice way :D The benchmarks are in https://github.com/TechEmpower/FrameworkBenchmarks https://github.com/TechEmpower/FrameworkBenchmarks EDIT: some preliminary results https://www.techempower.com/benchmarks/#section=test&runid=124fd2af-3030-4315-8876-e1db1fa91193&test=plaintext&l=hra0hr-35r https://www.techempower.com/benchmarks/#section=test&runid=1...
- kasey_junk 4y agoGo developers might though. A go library that requires native is a pretty big reason to avoid. Similarly a headline “c framework that uses libuv is faster than go fiber” wouldn’t cause an eye blink. So the concern is the title you used to get to the front page not the actual implementation.
- cirospaciari 4y agoI see, but like i said any performance focused Python framework are native (C/C++), so i will never be able to compare any Python framework with Golang framework ever.
- danmur 4y agoThe title seems accurate and appropriate to me. If I were selecting a framework for performance I might chose this framework, which I would use through Python, rather than a Go framework that I would program in Go. It's a framework, you use it with Python, and the performance is good (apparently, I didn't check).
- okaleniuk 4y agoGood point! However, you bring in a common misconception I'm fighting with within my company for a long time. Python is not an interpreted language. There is no such thing as an "interpreted language", a language is just a set or rules and keywords. Everything you can fit into Backus–Naur form is already a language even if it doesn't have any implementation nor compiler neither interpreter. Just as a piece of evidence, there are interpreted C++ (http://www.artificialworlds.net/wiki/IGCC/IGCC http://www.artificialworlds.net/wiki/IGCC/IGCC) and AOT Python (https://github.com/exaloop/codon https://github.com/exaloop/codon) implementations.
- RcouF1uZ4gsC 4y agoYou are missing the forrest for the trees. When people refer to a language, most often they are using it as a synecdoche to refer to the whole language ecosystem and not just the the formal language definition. If you look at the Python ecosystem, it is most definitely interpreted.
- nvrspyx 4y agoOff topic, but thank you for introducing the word "synecdoche" to me.
- narcraft 4y agoMovie recommendation: Synecdoche New York
- zelphirkalt 4y agoNow the question for non-native speakers is: How to pronounce that word? ;D
- somedude82 4y agoFiber is built on FastHTTP. If you know Go top "frameworks" performance characteristics then you would know that you are actually comparing HTTP implementations - ala whether framework is based on FastHTTP or Go standard library HTTP implementation. Framework own % there is for the top 5 almost non-existent. I would assume this is same case where - what ever Socketify is based on (pythons transport layer), is compared to FastHTTP. and mention of Fiber is click-bate.
- cirospaciari 4y agosocketify is based on uWebSockets (C++) uWebSockets is comparad to FastHTTP and socketify adds a lot of features on top. The benchmarks are TechEmPower plaintext https://github.com/TechEmpower/FrameworkBenchmarks https://github.com/TechEmpower/FrameworkBenchmarks preliminary results here: https://www.techempower.com/benchmarks/#section=test&runid=124fd2af-3030-4315-8876-e1db1fa91193&test=plaintext&l=hra0hr-35r https://www.techempower.com/benchmarks/#section=test&runid=1...
- deleted 4y ago[deleted]
- hnarayanan 4y agoWhat is Django Meinheld? They mention it in their benchmarks.
- cirospaciari 4y agoDjango is an WebFramework, Meinheld is an WSGI Server framework. https://github.com/django/django https://github.com/django/django https://github.com/mopemope/meinheld https://github.com/mopemope/meinheld So django meinheld is basically saying that i used Django served by meinheld in that benchmark.
- FpUser 4y agoI looked at the tests. There is nothing significant going on when creating response in http server for example. Just spit "hello world". So it appears to be a test of C++ uWebSockets and uSockets libraries vs for example native Go implementation. Do something serious in request handler using Python and then see what happens.
- cirospaciari 4y agoActually uWebSockets and uSockets will perform better than this (2x at least in my local tests), I need to do a lot of copying, instancing and crossing Python GIL. Yeah this test basically shows that Python backed by uWS is crazy fast, but is not an direct comparison to uWS to Go. This test is just an troughput test, with is very useful to measure raw performance. More tools like caching tools, a better database client etc is need to construct an complete scenario, and i'm working on it! (Maybe in 1 week or 2 weeks will be done) https://github.com/TechEmpower/FrameworkBenchmarks https://github.com/TechEmpower/FrameworkBenchmarks https://www.techempower.com/benchmarks/#section=test&runid=124fd2af-3030-4315-8876-e1db1fa91193&test=plaintext&l=hra0hr-35r https://www.techempower.com/benchmarks/#section=test&runid=1...
- FpUser 4y ago>"Python backed by uWS is crazy fast, but is not an direct comparison to uWS to Go." Correction. It shows that uWS is crazy fast. Sure if python us used as a thin glue between something like "select username from user" and uWS or send file over uWS then the result is fast. Do something meaningful in Python itself an it will be slow. This is not to diminish your work. Python is mostly glue anyways so in average the end result should be quite ok
- cirospaciari 4y agoI see your comment as positive <3 the whole purpose of this framework is to offer better glue, to Python for Web
- 4y ago
- js4ever 4y agoUWebsocket, the ultimate performance level!
- cirospaciari 4y ago<3 i will bring it to Ruby and Lua too!
- szastamasta 4y agoThis is kind of cool, but it all makes sense if your app is a very simple CRUD that spends 99% of time just passing json around. I have this feeling that when you add some more logic there you’ll start noticing that you’re not in a compiled language any more. Your requests will get slower and your memory usage will explode. Saying that Python is faster than Go with this as a proof looks like overreaching for Me. It only proves that wrapping C code in Python is fast. It’s an achievement, sure, but your app probably won’t be faster when you add thousands of Python lines between request and response.
- cirospaciari 4y agoi did not say that Python is faster than Go, i say that this Python Framework outperforms Golang Fiber framework in troughput. I used https://github.com/TechEmpower/FrameworkBenchmarks https://github.com/TechEmpower/FrameworkBenchmarks and in the future i will write fortunes and other benchmarks with have more things going on!
- melenaboija 4y agoIt does not say that Python is faster than Go it clearly says "Python framework". > It only proves that wrapping C code in Python is fast. Yes, it proves that for this specific use case Python is faster.
- meling 4y agoTechnically, it is C that’s faster.
- cirospaciari 4y agoPython (CPython) is written in C so always will be C, PyPy i think is C too? not sure.
- o_1 4y agoClaiming python has blazing speed while literally being CPython is insanity. This is like saying "Im a natural body builder who only uses Test, HGH, and Dianabol". Great drop the natural part, similarily just advertise speed as CPython.
- deleted 4y ago[deleted]
- znpy 4y agoI'm reading some arguments and counter-arguments in this thread, and in my opinion it kinda boils down to what point of view you're having. If you look at it as a framework that minimises the networking overhead, then fine, it's an interesting piece of software. If on the other hand you look at it like a "fast" web framework then things start to change and the discussion gets a bit more complicated. So for example, you look at the source code of the applications being benchmarked (example: https://github.com/cirospaciari/socketify.py/blob/main/bench/socketify_plaintext.py https://github.com/cirospaciari/socketify.py/blob/main/bench...) and you immediately see it's simply returning the string "hello world"). Which means that it's almost 100% of the time running in the fast path / best case. My guess is that as soon as you start doing any kind of computation in the request handler in normal non-super-optimized python (trival example: validating some headers and/or checking some signatures as you would do with jwt tokens for example) then the python-vs-golang gap will start to go back to favour golang. And then again, it boils down to what you're doing: anything io-intensive might benefit from the unetworking/uwebsocket beneath, anything cpu-intensive will benefit from the golang compiler producing native executable code. Nice work anyways.
- cirospaciari 4y agoActually the benchmark is on https://github.com/TechEmpower/FrameworkBenchmarks https://github.com/TechEmpower/FrameworkBenchmarks with is basically this with more headers, but you are right, is not enought, i used TechEmPower because is very popular. I have some issues (new features comming) open to create an better JWT token support, database and much more, i will post these in the future!
- deleted 4y ago[deleted]
- deleted 4y ago[deleted]
- ki_ 4y agosure it's faster.. but go gin and fiber are really slow. they are literally 90% slower than the fast go frameworks. Not that im a go fanboy, but to put things into context here, the actual context here is: python framework 5% faster than fiber and 85% slower than gnet/silverlining/gearbox.
- cirospaciari 4y agoFor sure have room to improve but is very competitive, i will try to archive the 7 mi inthe future, this is a very young framework, i will work harder! https://www.techempower.com/benchmarks/#section=test&runid=124fd2af-3030-4315-8876-e1db1fa91193&test=plaintext&l=hr9nun-35r https://www.techempower.com/benchmarks/#section=test&runid=1...
- ki_ 4y agohuh? waw. strange. there are 2 fibers on the benchmarks. 1 slow and 1 really fast. Same for socketify. 1 fast, 1 slow. Why is this?
- cirospaciari 4y agoone uses pre-fork the other do not use pre-fork
- cirospaciari 4y agoin the case of socketify is CPython and PyPy running the same code, but both are really fast, in the case of fiber is without prefork and with prefork variants.
- ulimn 4y agoHow is fiber slow? Can you please provide some source? According to the techempower fortune branchmark, it's the 3rd (prefork) and 6th (normal) fastest go framework and even in the all-language list it's 24th and 34th.
- Thaxll 4y agoSince we're in the useless benchmark, this Go native library completely wreck any C/C++ lib wrapped by Python: https://github.com/panjf2000/gnet https://github.com/panjf2000/gnet It is as fast as the fastest C++ / Rust implementation.
- maurice2k 4y agoAnd you can even beat this by using Golang's own net library and a pool (but not messing around with an own event loop): https://github.com/maurice2k/tcpserver https://github.com/maurice2k/tcpserver
- deleted 4y ago[deleted]
- jimnotgym 4y agoI'm feeling old. I went back to Flask recently and keep finding everything I know is deprecated, or not best practice any more. Then I read every week that some new framework is out that is better. I'm tired of it. I end up spending more time learning new things than I do building new things! Maybe I should get off hn for a while
- ccanassa 4y agoI worked on some REALLY big Flask projects over my carrer and I came up with my rule for it: "Any sufficiently large Flask project contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Django." Just sticky with Django. It's stable, well-maintaned and includes most batteries out-of-the-box.
- aliqot 4y agoDon't judge your insides by other people's outsides.
- maroonblazer 4y agoI like that. I'd not heard that line before and wanted to find the source. Surprisingly, Rob Lowe heard it from someone in AA. https://www.youtube.com/watch?v=UNQcFjIOfCE https://www.youtube.com/watch?v=UNQcFjIOfCE
- cirospaciari 4y agojust follow your heart <3 take a breath, just do what you love and makes you happy.
- exabrial 4y agoIt’s not you getting old, it’s you going tired of the pretentiousness of that pervades the industry right now.
- fbn79 4y agoThe secret is stop using frameworks and use just libraries (even the latter with parsimony)
- onedognight 4y agoThe “src/“ directory[0] contains compiled .so files. Is this even open source? [0] https://github.com/cirospaciari/socketify.py/tree/main/src/socketify https://github.com/cirospaciari/socketify.py/tree/main/src/s...
- kapilvt 4y agoNavigate down another directory to `native` directory which has the source for the .so files.
- cirospaciari 4y ago.so are the pre-built binaries but you can see the native folder code there and also see the projects used in Makefile
- xwowsersx 4y agoHmm... there's Python and CPP. src/socketify ├── __init__.py ├── __main__.py ├── asgi.py ├── cli.py ├── helpers.py ├── libsocketify_darwin_amd64.so ├── libsocketify_darwin_arm64.so ├── libsocketify_linux_amd64.so ├── libsocketify_windows_amd64.dll ├── loop.py ├── native │ ├── Make.bat │ ├── Makefile │ ├── src │ │ ├── libsocketify.cpp │ │ └── libsocketify.h │ └── uv_selector.txt ├── native.py ├── socketify.py ├── ssgi.py ├── status_codes.py ├── tasks.py ├── uv.py ├── uWebSockets └── wsgi.py I think the .so files are built from other source though? I'm not sure. In the makefile they are rm'd and then created. The linux workflow file, for example, has: make linux cd ../ git add libsocketify_linux_amd64.so
- cirospaciari 4y agoyou need to pull all git submodules too git submodule update --init --recursive --remote
- onedognight 4y agoAh, thanks! In my defense, the native/ directory contains the portable C++ source and the src/ directory contains a the native executables.
- corluxrycleng 4y ago[dead]
- ktzlf 4y agoI assume that if this C-extension is faster than Golang Fiber, it is way faster than asyncio! And it would have been the same with Python 2.7. This demonstrates yet again that the main value of Python has always been C-extensions. The efforts of the old boys to add bloat in Python 3 (mostly written by other people of course, the old boys talk and rarely develop) have been misguided.
- deleted 4y ago[deleted]
- commitpizza 4y agoVery cool, I will bookmark this since I am out on a look for a new backend framework for an api I am building.
- cirospaciari 4y ago<3 if you need help just open an discussion on github or send me a message on discord https://discord.socketify.dev/ https://discord.socketify.dev/
- commitpizza 4y agoSorry for all the hate you seem to be recieving, I think it looks great! I can't join the discord however since I was banned for unknown reasons and cannot create a new account without giving them my phone number, which I refuse to do. But remember many great things get hated upon in the beginning, take dropbox as an example. People on HN thought it was a shitty idea and they seem to be doing just fine :)
- cirospaciari 4y ago<3 thanks thats means a lot, i will focus on positive comments and constructive ideas, and keep working hard to do my best.
- cyber1 4y agoYet another "X faster than Y" where inside X all hot jobs are done by really good-tuned C or C++. Facepalm. Without real problem-solving (business logic) written in Python, this is only lightweight wrapper on C/C++. When the number of Python code start growing in the hot path, then these blazing-amazing thruput numbers tremendously will be going down.
- inglor 4y agoI'm so happy this is (currently) the top comment and people are starting to realize measuring perf with these well tuned micro-benchmarks is a sham.
- jwdunne 4y agoYes. I was thinking exactly this when coming into the comments. Real world benchmarks take more time to prepare, we get that, but let’s be honest: a bold claim _needs_ bold evidence.
- warinukraine 4y agoWhy is it a sham? It's useful to know that x is faster. As a user of x I don't really care if the reason it's faster is it's C++ under the hood. That's really an implementation detail for me.
- lupire 4y agoWhat happens when you use X because it's fast at one thing in a microbenchmark, but it locks you into an environment that is slow at the rest of your program?
- inglor 4y agoBecause it's measuring a scenario that's not representative of real usages of X and is usually tweaked for the framework/tool the author is trying to showcase. For example: all the deno/bun benchmarks often use the Node.js frameworks in an unnecessarily slow way and don't measure apples to apples. (like using uWS in bun but not uWS for Node in the benchmark). This one in particular just measures the speed of "hello world" in plaintext and JSON with very specific parameters.
- kamikazechaser 4y agoWhen can we see a fortunes benchmark or one with any popular python sql driver? .NET were gaming their techempower benchmarks to advertise they were blazingly fast. Turns out, not so fast with real-world code.
- deleted 4y ago[deleted]
- gregors 4y agoI don't quite understand the corking documentation. Is this like TCP_CORK? A buffered/batch send? Can anyone point me to details? https://docs.socketify.dev/corking.html https://docs.socketify.dev/corking.html https://baus.net/on-tcp_cork/ https://baus.net/on-tcp_cork/
- cirospaciari 4y agoFrom uWS docs basically "sends into one single syscall/SSL block", in my understanding corking is basically minimizing to much sends, so it's batching calls.
- jerf 4y agoA good example of why web servers should be measured in seconds per request rather than requests per second. As you trim little tiny bits off the seconds per request, the requests per second go skyrocketing off to infinity, but unless you're doing zero work per request, that's a dubiously useful metric. 1,000,000 requests per second on what I think is an 8-core system (?) is 1/1,000,000 * 8 = 8us per request. 1,250,000 requests per second would be 6.4 us per request. Is this really your make or break issue? There's a set of people who can say "yes" to that. There's a set of people who think it is yes. The latter is much larger than the former. (Although arguably the ones worst off are the ones for whom it is their make-or-break issue, but they don't realize it....)
- deleted 4y ago[deleted]
- Thaxll 4y agoWhen I see that: https://github.com/cirospaciari/socketify.py/blob/main/bench/socketify_plaintext.py#L22 https://github.com/cirospaciari/socketify.py/blob/main/bench... It's kind of hopeless, Python still needs to fork per core to get any performance? So if you have 8 cores you're actually running 8 processes, so 8 DB pool etc ...
- cirospaciari 4y agoPython GIL is the problem for multithreading, but I think I have a solution to not need 8 DB pools, soon o will post about it. But yeah it's a waste
- tomwojcik 4y agoOh, I have a pretty fresh news for you. https://github.com/python/peps/pull/2955 https://github.com/python/peps/pull/2955
- jopython 4y agoI wouldn't be excited about PEPs. GIL has been talked about for umpteen years.
- cirospaciari 4y agoWOW that's awesome!
- simonw 4y agoWhy does that feel hopeless to you? Running one process per core has been working well for scaling huge websites for decades at this point.
- cirospaciari 4y agonodejs do this and actually Go fiber uses prefork to do this too
- cirospaciari 4y agoThanks for all your support and feedback, if you want to see any new features requests, or have any questions related to the project I will be glad to help you <3