There are. Any language that supports either fastcgi, or runs as an apache plugin (or similar) functions in the "each request starts new" space. There's certainly others, but Python and Perl are both good examples.
Starting new with each request does, of course, mean lots of re-work that shouldn't have to be done with each request. It does initially keep complexity down, but at scale, the applications I've worked with have to use a shared cache (like acpu) to avoid that rework and meet performance goals.
I know it can result in a lot of "extra work", but I really feel like most of the pain of that could be abstracted away by the runtime.
Nginx/apache setup a PHP process before the request comes in, so why couldn't you expose that point to your language and let the programming language do work before that point, even "snapshot"ing it to avoid re-doing that work for each request?
It just seems like there are better ways of solving this problem, because an event loop is such a "hammer" solution to the problem.
(On my systems, by default there is some reuse of the loaded module, so you can leak state between requests. However it should be possible to avoid reused processes).
import cgi
Also, the httpd communicates to the CGI program via environment variables so one can also write their program in assembly.You also need to restart apache or change the wsgi loader file, (or set up explicit hoooks to do so) to get your new code to appear when debugging / after uploading changes. This is where I'd say php is superior (upload file, refresh browser).
There's actually work being done to build PHP frameworks that get around this with ReactPHP, ZeroMQ, Photon, etc. Essentially this is what HHVM does as well, by at least keeping your compiled bytecodes in memory (similar to APC/eAccelarator/ZendOptimizer, etc).
See: http://reactphp.org http://www.photon-project.com https://gnugat.github.io/2016/04/13/super-speed-sf-react-php...
Even the idea of an alternative runtime for PHP (ala HHVM) is nothing new: http://quercus.caucho.com
So? If it takes < 1ms, what's the harm? And opcode cache comes out of the box and most PHP DB drivers can use connection pooling.
We serve most of our requests in < 10ms, and we're not even on PHP7 yet.
All the magic you ever need can be dynamically created in __get, __set and __call. It works, it works well, and it makes not only reasoning, but also deployment an order of magnitude simpler.
>Code paths, auto-loaders, database connections, config files, etc.
Use a single code path, a single autoloader and a single database connection. Cache the opcodes of stuff you load. Write config files and templates in pure PHP, so they're cached as well. Done.
I've never, ever had problems with bringing PHP page generation time below .1 seconds. Usually it took something like .03 seconds on crappy hardware. And that was without extensive caching of DB results or anything else that's particularly clever.
Do you most of those need to happen at all, ever? In my mind, auto-loader is a sign that nobody knows what's being loaded (if they did, they would just require it). Requires should be full pathed (because have you seen what happens when you search the include path). Mysql_pconnect has been doing connection pooling for a long time, mysqli supports it too (so yes, you do need to connect sometimes), anyway, if you're loading a framwork, loading that probably takes longer than connecting to a mysql server in the same colo.
Every wasted millisecond on the server side matters. It impacts scalability, customer experience (and revenue) etc. You should take every easy win you can get there.
Not doing full includes is just ridiculously lazy. It doesn't take that long to write them out, and your IDE can help you out there. I bet you spend more time on social media during office hours than you'd ever save from not having to type out those import statements.
Or the IDE. IntelliJ or ReSharper does that for me. And I like dealing with any naming conflicts right then and there, which those tools allow me to do.
I see that you've never worked on a project where the CPU time needed to handle the traffic with crappy code is much more expensive than developer time to write efficient software.
Burning cpu and maybe i/o looking for code all over the place is going to make it really hard to make it fast later.
Or that, you know. There is an extremely powerful language feature and the developers are taking advantage of it.
Well, it depends on how it's implemented, and how pedantic someone gets about what "shared nothing" means.
There is a long history of unix daemons that initialize, listen(), and then fork off a child process whenever a client connects. The child does all the work and the parent goes back to listening. You can do the "up front" work once and then each child can only modify their copy of the data, preventing it from interfering with the next request.
> It seems like it would be easier for everyone involved. You wouldn't need much of a GC when the process is killed every time, you don't need to worry about async IO or multi-threading or catching errors or any of the other annoyances that come with most of the traditional "event loop" way of doing things.
Firing up a new process (or even a new thread) for each request is very expensive--much more so than a generational GC. Async IO also mitigates this (why have 10K parked threads consuming memory all your memory if all of them are stalled, waiting for database)? Services that spawn a thread for each request run into the C10K problem--they can only serve 10K simultaneous clients. Regardless of your concurrency model, you can't ignore errors--you still need to dispatch the right status codes and error information (not to mention logging, etc).
You should check out Go. You write concurrent code and the runtime effectively manages a thread pool under the covers so you get all of the performance benefits of async programming with the developer-friendliness of synchronous programming. In the case of a web app, you just need to write your request handlers--the web server manages the request concurrency for you, and the language's runtime manages the parallelism.
True, but I'm not aware of any notable language that did it differently in the mid 1990's when PHP was rolled out. PHP does not spawn a new OS process per request these days. It does spawn a new interpreter, but not a new OS process. Combined with the now bundled opcache, the re-work per request is limited to the developer's own initialization code if they don't choose to use a user-space shared cache.
The OP's question wasn't scoped to the mid-90s.
> PHP does not spawn a new OS process per request these days. It does spawn a new interpreter, but not a new OS process.
Like I said, the same holds true even for an OS thread. Anyway, if it's not a new OS process, then some sort of GC is needed, contrary to the OP's statement.
> Combined with the now bundled opcache, the re-work per request is limited to the developer's own initialization code if they don't choose to use a user-space shared cache.
Again, these are all solutions to problems PHP invented for itself. Other languages don't require special caching mechanisms; they get by on normal scoping rules and shared memory.
With PHP you can see your program as a pure function whose result depends only on arguments. You don't have to care about memory leaks like you don't have to do memory management when you have a GC. And if you want more performance and less convenience you can always opt into running your own web server.
> Don't use global variables
If you have an object that is persisted between requests you already have some state that is saved.
def __call__(self, request):
client_ip = request.META['REMOTE_ADDR']
self.last_visitors.append(client_ip)
...
This code follows your scoping rules but still leaks memory. So it looks like you don't understand why memory leaks occur. I explained somewhere in ancestor comment that to prevent leaks you either need a language with pure functions or reset environment on each request, none of which is possible in Python yet the latter is available for PHP users.With Django processing model any array can become the source of a memory leak. I have heard that Ruby and NodeJS developers often have to restart their applications every several hours because they even have no tools to find the source of a leak. The problem that does not exist in PHP by design.
Which isn't what PHP does, fwiw.
And you can also set up Ruby, Python, Rust, Haskell, Java, etc to create a new interpreter/vm/whatever for every request. All of those languages have libraries to support CGI. Using the same OS process but restarting the interpreter/vm will be a bit more complex, but absolutely possible. You can even implement the "every file is an entry point" approach for at least Python and Ruby.
The difference is what is the intended use for each platform. E.g. creating a new OS process, loading the PHP interpreter, bootstrapping Wordpress, getting some data from the DB and rendering a page is possible under 600ms while creating a new OS process, loading the CPython, bootstrapping Django, getting some data from the DB and rendering a page will easily take you 4 seconds. This is because Django developers didn't expect you'll be doing that, so they put a lot of stuff in the initialization step (system checks, creating db connections, setting up logging, ...).
This was never actually an asset. Startup times were huge, lack of shared state meant extra requests to database servers (and to memcache instances to avoid database round trips) to get the same data per-request. Each request got longer and a given page or api call might issue many duplicate requests in a short period of time.
Plus since PHP doesn't have viable threading or async (definitely didn't at the time) each memcache or sql request had to be synchronous, resulting in even more wasted time. At the very least memcache had good support for batch operations so we could manually batch our queries.
Overall though this is not an asset. It's only the 'best' part of PHP if you don't want to think about writing good software that manages shared state.
To be fair, many applications don't actually benefit from being good code, so PHP is probably a good fit for those.
Here is an example in C: https://www.cs.tut.fi/~jkorpela/forms/cgic.html
Php was born out of trying to reduce a lot of that cruft and blending code and html output easily. And that's what initially made it a winner.
Which should be near 0 if you can be bothered to enable OPcache in php.ini. Not only parsing/disk reading but also bytecode generation are bypassed.
In PHP, persisting this sort of thing between requests becomes a painful task instead of a triviality
apc_fetch/apc_store hardly seems painful.
Not to mention, all the other languages out there memcached just as well.
The alternative is crazy sharding systems which are becoming more and more difficult as devices are less and less "static"
A bit tangential, but I find myself disliking it too, for no good reason that I can think of.
Perhaps it's something of a crutch in that it's really "I like it more, but 'reason' sounds better" ? Not sure that's quite it, either, as in the above case with a "new everything per request", it's certainly true that it's easier to think about what's happening.
The phrase has a high correlation with subjects that are themselves highly correlated with smug proponents; functional programming is one of the greater ones of these.
Personally I like the phrase. Then again I self-identify as a (non-smug) SmugLispWeenie[2] so of course I like it.
[1] https://www.infoq.com/presentations/Simple-Made-Easy [2] http://web.archive.org/web/20160709054130/http://c2.com/cgi/...
You can get the same reasoning benefits in pretty much any language by just not using any global variables. Yes, you're still running a framework/server with internal state, but with PHP you've got the same "issue" with Apache/Nginx.
You are running it from RAM. PHP's OPcache, and HHVM, will both compile the code only once (well, HHVM will compile it multiple times due to JIT, but it only touches the disk once) and cache it.
Define "very". Because for me it's more like "a few hundred microseconds per request".
And even if you cache everything, you still have the code necessary to setup the runtime environment of you application which runs on every request and does the same thing.
But still, I do actually like that model and it does have many advantages for development. But it's really hard to work in PHP, the language, after using something better.
For the conversion to bytecode, that is what apc is for.
But also, you don't typically use lambda to serve pages or a full application, more commonly it's used for specific processing tasks, individual endpoints, and generally code that can run standalone.
Other languages, whether directly or indirectly manage cleanup via GC or recycle processes, like UWSGI for Python.
I also don't find any particular benefits over other languages with "reasoning about". As a PHP application grows and a team restructures it into something more mature it ends up looking the same minus the event loop (which just lives somewhere else).
Yes, you do. You'd be surprised how easily memory balloons out of control unless you regularly run a GC. Log minor collections sometime in Java or JS engines if you don't believe me…
Even worse, if you don't run GC regularly, you will suffer terrible locality as execution continually grows the heap (not to mention the overhead of continually requesting free pages from the OS).
It's not an insane idea - CGI worked exactly like this, as do most command-line shells. And the overhead is often less than most people expect, since most pages are COWed on fork() and the files it touches will likely be in the filesystem cache. Still, I think people found that the overhead from process creation (and in particular, keeping all those processes around & task-switching them while they make DB/network/filesystem calls) was greater than that from GC, and so most frameworks - PHP included, these days! - use a more lightweight mechanism.
Not that I feel cgi is the most efficient way to handle requests... but not needing the complexity of GC could be one advantage of that approach...
I speak from experience: there have been many attempts to mandatorily delay collection until the end of the event loop in browsers, to achieve greater responsiveness. It has always failed. You can add heuristics to try to preferentially collect at the end of the event loop, but you really need to be able to GC anytime.
However, if you're handling requests well within a given memory threshold, it isn't always something you should worry about until it becomes a problem. In which case, you'll probably want to look at something like go, rust, erlang or others to handle improvements, or break off heavy parts into sub/micro-services.
Any recommended places to start with?
So this process-per-request thing is not exclusively a Php thing.
I completely understand the "trendy" part. Sadly even language/frameworks need marketing, and doing things in a "wasteful" and "slower" way but simpler is gonna be a tough sell even if it might be the best move.
I just feel that there is a space for a "better PHP". One that uses a better base language, but still keeps the benefits from the language like the simplicity of the "think edit reload" cycle, the shared nothing architecture that makes programs easier to write and simpler to test, and the horizontal scaling.
[1] https://git.zx2c4.com/cgit/about/
P.S. An important thing that contributes to the success of PHP is the amount of hosting services that support it.
About 2-3 orders of magnitude in performance. That’s the catch.
And it’s the reason why even with PHP you use things as opcaches, cache database results in external daemons, you use process pools with fastcgi instead of actually creating new processes, etc.
And hacking those things on top of PHP make your program even worse to reason about than just using a daemonized system with actor framework.
> And it’s the reason why even with PHP you use things as opcaches, cache database results in external daemons
You make it sound as if the idea of caching was invented by PHP programmers to address language deficiencies. Nothing can be further from the truth. Everybody uses caches, because it's faster. If you don't use DB cache, there's no way in the universe you can make you app fast under any significant load.
> And hacking those things on top of PHP make your program even worse to reason about
You have very strange view of performance design if you think using caches is "hacking something on top" and has to be avoided.
> than just using a daemonized system with actor framework.
This looks like a complete non-sequitur - you could use actor framework and still use all the things described above, and do it in PHP, and thousands of people do exactly that. On not in PHP, if you'd like - this pattern is completely orthogonal to the language used.
I had a side project written in Elixir/Phoenix make it onto the front page of HN and it indeed was the case that the majority of requests were in hundreds of microseconds. The default log messages actually use "µs" which is kind of cute.
I wrote about it here[0] and extracted a random sample of my logs and you'll see that most of them were in the hundreds of microseconds.
Disclosure, I worked at GD in Website Builder when this was being developed, but haven't been there for over 2 years now.
Yes, they do. Phoenix/Elixir is a nice way to get below the millisecond, and even with Java you can for most requests go below a few milliseconds.
And you can obviously handle far more requests at once, as you have all the code already loaded in RAM, and just need to jump into it, instead of reparsing it, or copying it back from a cache.
People go to a lot of trouble to optimize the front end system, but tie it all to the same database that bottlenecks well before the web server. There are certainly times where PHP or CGI aren't fast enough for the job, but I think people tend to unfairly blame them in situations where the underlying problem is more systematic.
that's not true. especially not in the DaaS space.
If you need to process thousands of requests per second per thread then don't use PHP, but that's a rare situation. I wouldn't build RTC in PHP. But web or enterprise applications, which are by far more common, don't really suffer that issue.
And pretty much everyone caches database results...
Compared to the other offerings, it's on par or faster (Python and Ruby really have a lot to be desired). You're talking about an actor framework, which is more performant at a cost of using that model and the myriad of issues with managing a more complicated system. The market favors simplicity and less sophisticated developers, in most projects.
A rewrite I worked on, from PHP to C++, had an improvement of 20 times better performance.
That's only one (1) order of magnitude.
Compare Symfony2 with Spring, for example (~500 vs. ~22'000 responses per second).
Or if you want to only use the raw language itself, php-raw with ulib-postgres (~90'000 vs. ~300'000 responses per second)
And with PHP, the larger the codebase, the slower it always responds, because even with opcaches loading it into RAM is a major bottleneck.
That’s exactly the issue at hand here.
And compare actual performance, for example JSON serialization, that’s not even fair anymore, symfony2 reaches around ~2'000 a second, gemini, the fastest fullstack framework, reaches ~970'000 a second.
Raw PHP reaches still ~170'000, but the fastest non-PHP raw language is still at ~2'200'000 compared to that.
These are actual performance issues that will cost you actual money. Even saving 20% of hardware and server costs can be the difference between your company being cost-effective and dead.
PHP is no more stateless than any other language out there. Statelessness is a design choice, not something PHP gives you for free. If your app write things on the local disk or use the default PHP session handler then it is not scalable by default. In order to write code that scales you need to make it scalable, it's not something automatic and certainly not special to PHP.
The catch are couple.
First Concurrency is _hard_ and relying on the OS scheduler would have been really har don ressource until recently, which is why nearly noone did it.
That used ot be a wart of php, only hidden by Moore's Law and recent work on OS schedulers.
But yeah. Erlang do this since the 80s
Actually I have never seen that this was a problem in practice with the application server model. I therefore don't think this is a relevant argument.
You can do the exact same thing with any language that supports CGI. You can compile a Go binary, put it on an Apache server and you'll get the "shared nothing lifecycle" just like PHP.
Isn't there a downside to that? If you want to do multi-threading, you can't just do `ThreadPool.StartNew(() => doSomething())`. You're SOL.
It’s really interesting, last time I worked with PHP was a few years ago, then recently I wrote something in PHP 7, and it is a lot safer.
(But still no compile time type checking because there is no compile time).
Why are there no other "competitors" in this space? Why do most other languages go with the alternative route of using an event loop or daemonizing your "server" to serve up requests? I can understand why Node.js does it (otherwise the async nature would just be an annoyance for no gain), but why haven't there been any other server-side languages that not only work well like this, but actively target it?
It seems like it would be easier for everyone involved. You wouldn't need much of a GC when the process is killed every time, you don't need to worry about async IO or multi-threading or catching errors or any of the other annoyances that come with most of the traditional "event loop" way of doing things.
So what's the catch?