World's "Fastest" Small Web Server Released, Based On LISP
Cougem writes "John Fremlin has released what he believes to be the worlds fastest webserver for small dynamic content, teepeedee2. It is written entirely in LISP, the world's second oldest high-level programming language. He gave a talk at the Tokyo Linux Users Group last year, with benchmarks, which he says demonstrate that 'functional programming languages can beat C.' Imagine a small alternative to Ruby on rails, supporting the development of any web application, but much faster."
In speed and elegance, perhaps. But not on the überprogrammer salary to maintain it.
It's disgusting that these LISPers aren't content with their own perversion, but have to try to attract others to the gay lifestyle.
You might also be interested in SMLserver which embeds Standard ML into Apache, and apparently is pretty fast.
-- Ed Avis ed@membled.com
Not at the expense of having to learn LISP! I'd rather use dialup.
And Java is faster too!
(rolls eyes)
Different tools are good for various solving various problems.
Yeah, I know certain library routines in certain languages are better than others.
Interpreted languages, in general, are not faster than compiled languages. Period.
This "faster than C" canard keeps getting trotted out and shot down every time.
Well, there is one language faster: assembly.
Sorry its the third oldest this is the oldest.
Designed by Konrad Zuse who also invented the first program-controlled Turing-complete computer. Fortran is the second oldest programming language.
"Automated garbage collection is rubbish" and "Real men don't use floating point" were two of the most interesting and compelling arguments I've read all week. And using LISP as a web platform framework? Fascinating. There were some great ideas back in the days when computers were in there infancy and a lot of them have been abandoned for the most part. Like trinary computing for instance. The building blocks of the computers that you see today were partially designed because of technological limitations at the time. The mechanical underpinnings of the first computers are still present today. I don't care if I'm really wrong about this point (I've been wrong before), but I think computing really needs to transcend a system based on 0s and 1s. Why not abandon the general purpose cpu altogether or at least reduce it to a single core and focus on multiple cores of different types of chips that are optimized for different types of problems? Larrabee might be an hint of that, though I think that ultimately it will really just be a cost saving measure since the gpu no longer needs to be integrated into the board. I think we may be locked into a future of x86 clones for another 30 years at this rate. The Itanic was a good lesson for intel in how much the market values their older code still being able to run without issue. Forgive my bit of a ramble. Just had a whole bunch of random thoughts there.
zosxavius photography
It can be, but any decent production implementation is compiled to native machine codes -- it just includes compiler (and usually pretty fancy optimizing one!) built into the image and always available.
Try running, say, SBCL one day before spreading misunderstandings...
Paul B.
the LISP language itself is written in C.
Not at all. Lisp implementations are usually written in Lisp.
Even though Internet throughput seems to be increasing (bandwidth) in leaps and bounds, the server is often a bottle-neck.
What ? You can buy a quad-core, multi-gigabytes-of-RAM machine for under US$500.
For web serving, if your webserver hardware is the bottleneck, You're Doing It Wrong.
In speed and elegance, perhaps.
So you agree to the fact that emacs is faster and more elegant than vi, right ? You agree ?
Based on my theoretical understanding of how computers work, I though HTTP daemon performance depended mostly on
Would someone care to correct me?
Note that TFA (well, the slideshow) measures performance in requests per second. That's a very useful measure, but it's compared to Ruby (Mongrel?) and PHP (Apache?). I'm not sure what that comparison means. Does Apache not support lisp, or only as CGI?
Is there something stopping Apache from being sped up? Is he measuring the performance of LISP, or the performance of a HTTP daemon?
I'm a bit confused...
Today is Memorial Day in the United States of America. We would appreciate you folks taking some time to reflect on our servicemen who gave their lives saving your asses in WW I and II.
We do that on Nov 11, thanks. I don't see why we need to adopt your dates for the purpose.
C is more readable, though.
Of course, this guy didn't benchmark against any modern performance kings, such as Nginx, YAWS, htstub or LightStreamer.
There is no reason to believe this is the world's fastest webserver, and I'm sure as hell not holding my breath.
StoneCypher is Full of BS
I think there is an implied "still in use" in the statement - otherwise this is a list - http://en.wikipedia.org/wiki/Timeline_of_programming_languages suggests there are older ones still, and Lisp wasn't even third by any stretch.
[Lisp] can be [interpreted]
Actually, Common Lisp cannot be implemented as a pure interpreter -- there are a few features of the language that you cannot implement without performing a pass over each function.
(Scheme, the other dominant dialect of Lisp, can be implemented as a pure interpreter, a pure compiler, or a hybrid design.)
Your current soldiers are solid. Your previous soldiers were solid. This isn't a pissing contest, but when it comes to having historically solid troops I think we, at least, have earned the right to reflect on the sacrifices of our respective troops on different days *. Yours on your day, and mine on my day. Which is to say, we know it's memorial day. Your soldiers are and have been heroes, but keep your holiday to yourselves. Just as the rest of us keep ours to ourselves.
* - it's worth noting (though I can't find the citation) that the method by which the cdns held kapyong against the 3-5:1 odds was by calling down artillery on their own position
Oh god, that woman is John Romero!
I first learned LISP using the watered down version included in AutoCAD while writing huge customization projects in the 80's. I loved the language so much I dove into it full force and enjoyed it thoroughly. To me it was so inherently elegant I wanted to use it everywhere. Obviously however making a living meant most of us had to focus our energies elsewhere but something like this makes me all giddy again. I think I have some playing to do!
Play me online? Well you know that I'll beat you. If I ever meet you I'll "/sbin/shutdown -h now" you. -Weird Al, kinda.
... so I guess it's not fast enough.
We do that on Nov 11, thanks. I don't see why we need to adopt your dates for the purpose.
But... but... Nov. 11th is a horrible date for outdoor grilling! That would ruin the holiday entirely. I don't think you really grasp what Memorial Day is all about...
"Convictions are more dangerous enemies of truth than lies."
You aren't looking very closely if you're missing it.
By "c-like" I believe Graham meant elements of syntax and approach.
methods declarations in Java take the form:
return_value name(args)
{
statement;
data_structure.member = assignment;
}
A C function looks like:
return_value name(args)
{
statement;
data_structure.member = assignment;
}
The approach stuff is harder to summarize in a post but think of the differences in the use of macros and differences in binding as good examples
James Gosling is one of the people who called Java a "C-like language that avoided the pitfalls of C++"
(full disclosure: I used to work for Sun as a Senior Java Architect so my opinion may colored by the chip they put in my brain)
[-- Trust the Monkey --]
Hah. Last time I used LISP (well, really, Scheme, since it was at Berkeley), I was on dial-up!
I remember thinking that there might be something wrong with the dial-up connection the night before the first big project was due, so going into the lab at 2am. The dial-up was not the problem, as it turned out. It was the fact that I wasn't alone in waiting until the last minute to test my code. There were 500 students on that brand new DEC 5400, all writing recursive, interpreted code, and apparently doing so badly enough that such difficult tasks as accepting a username and password were beyond the abilities of the server.
The CB App. What's your 20?
This web site was cited in the Wikipedia artical posted by the parent.
English is not this
In terms of readability and maintenance it might be a nightmare (looking at the LISP code). The benchmark seams biased anyway, you can't beat C/C++, really, and the LISP language itself is written in C.
Very few implementations of Lisp are written in C. Usually there is only a small kernel, and on top of that kernel sits the standard library and the compiler. The kernel often provides only the memory model, the garbage collector, and links to the OS - only the things that can't be written in Common Lisp are in C. Mind you, they *could* be written in some "lower-level Lisp", but since the passing away of Lisp Machines, which ran Lisp Assembly code, nobody seems to bother with this - portable C compilers are ubiquitous and the core itself is portable this way. This means that a compiled Lisp program runs essentially very little C, unless it is collecting garbage.
The reason for Lisp being written in Lisp is precisely what you're claiming there (only the other way round): A Lisp written in Lisp is much more maintainable than a Lisp written in C. Besides, compiler often serves as a good test suite for itself.
And as far as "beating C" is concerned, you might want to take a look at Stalin Scheme.
Ezekiel 23:20
It has one and only one error message: "Missing Parenthesis" ;-)
Table-ized A.I.
Reason being is that C is the closest high level language to how a processor actually operates. A lot of people get confused, or perhaps never really know how a CPU actually works and that no matter what language you code in, it all gets translated in to machine language in the end.
Now what that means is that there are certain things that, while convenient for humans, have nothing to do with how the processor actually thinks. A good example would be newer replacements for pointers. A lot of people hate pointers, they claim, correctly, that pointers are confusing, and that you can easily cause problems with them. That is all true, however it is also how the CPU actually thinks. The CPU doesn't have advanced concepts of references and of garbage collection and so on. The CPU has data in memory, and pointers to the location of that data. It doesn't even have data types. The data is just binary data. You can store a string, and then run calculations on it using the FPU. Granted you'll get garbage as a result, but there's nothing stopping you from doing it, the CPU has no idea what your data is.
So, the upshot of this is that C is very close to the bare metal of how the system works. Thus if you are good with it, you can produce extremely efficient code. The higher level stuff may be nice, but it all slows things down. When you have a managed language that takes care of all the nasty stuff for you, well it is spending CPU cycles doing that. Now the tradeoff is quite often worth it, since CPUs have loads of power and maintainability of code is important, but don't trick yourself in to thinking it is more efficient.
You have to remember that no matter what, there is one and only one way that the machine actually thinks, one way it actually processes information. All the nifty high level programming shit is just to make life easier for the programmers. That's wonderful, but it doesn't give you the most optimized code. Of the high level languages, C retains that crown, and likely always will, because it is the closest to how a CPU actually works. I've seen the joke that "C is a language with all the speed of assembly and all the ease of use of assembly!" There's some truth to that.
So I have to agree with the grandparent. If the LISP heads think LISP is faster than C, they are kidding themselves. I'm not saying a good LISP program can't be faster than a bad C program, but if you have equal skill in optimization, sorry C will win out because in the end it will generate more efficient machine code and that's all that matters. All the theory of different programming paradigms in the world isn't relevant to how the CPU is actually going to do things.
"... C is the closest high level language to how a processor actually operates."
C was meant to be equivalent to a high-level assembly language. Someone told me that he was worried about coding in assembly language for a particular part of a video driver, but he discovered that, in that case, his C compiler wrote perfect assembly language.
Once you get things like branch prediction, speculative execution and pipelining into the picture, no, C isn't really any closer to how the processors operate. Making efficient use of a modern CPU involves detail at a much, much lower level than C exposes.
The performance killer for high-level languages isn't really the abstraction away from the machine instruction set; it's garbage collection. And even then, it's mostly because GC tends not to play well with memory caches and virtual memory; a simple stop-and-copy garbage collector is actually algorithmically more efficient than malloc/free, but absolutely atrocious with caches and VM.
Are you adequate?
Repost - lt should be replaced by lessthan sign...
Trolling sure sounds easy, but...
Gambit-C Scheme vs. C
I'll make it easy for you. It's the two minute litmus test. Even easier -- I'll give you the pseudo-C code:
Task: compute n! for n >= 1000.
In Scheme (Gambit 4.2.8, using infix):
int factorial(int n) {
if (n lt= 0) {
1;
} else {
n * factorial(n - 1);
}
}
compile with: gsc f.six
and run it:
gsi
Gambit v4.2.8
> (load "f")
"/home/user/f.o1"
>(factorial 1000)
4023...0000
Your challenge? Write a C version in two minutes, tested and compiled. Now, as the final icing, run the C version on smaller numbers, and compare the performance -- did you forget to compile in small integer versions? (try factorial(12) a million times).
I'll wait (another two minutes). Compare the performance against the LISP version. Did you have to write two versions -- one for big integers and one for small integers? That is pretty well the only way to keep a speed advantage... I hope you wrote it that way. Did you remember to put in 32/64 bit conditionals to retain your advantage on a 64 bit platform?
I think your C code now looks like this (it should):
#define FACT_LIMIT 12 -- for 32 bit int type, I don't know what the cutoff is for 64 bit. /* This only gets executed a maximum of FACT_LIMIT times; leave it recursive */ /* May wish to rewrite to an iterative form */
#include bignum.h -- I don't want to bother with quoting assume angle brackets
int fact_integer(int n) {
if (n lt= 0) {
return 1;
} else {
return n * factorial(n - 1);
}
}
bignum factorial(bignum n) {
if (compare_lt(n, FACT_LIMIT)) {
return int_to_bignum(fact_integer(bignum_to_int(n)));
}
return bignum_mult(n, bignum_dec(n));
}
You choose the bignum package to use. Or, for more fun, write it yourself. If you wrote it yourself, you remembered to switch to FFT style multiplication at bigger sizes? Or Karatsuba?
Now, we have only coded to a recursive form, but, since bigints are not first-class in C, we don't know about memory reclamation (leakage). I hope you know the gmp library, or can roll up a gee-whiz allocator on your own. The gmp library would be cheating, by the way -- YOU DID CLAIM YOUR IMPLEMENTATION IN C.
If recursion is viewed as a problem, the Gambit-C version can be recoded as:
int factorial(int n) {
int i;
int a;
if (n lt= 0) {
1;
} else {
a = 1;
for (i = 1; i lt= n; ++i) {
a *= i;
}
a;
}
}
I am sure that something equivalent can be done in the C version. But the normal flow of control stuff doesn't know about bignums. We COULD make the incoming parameter an int, I guess... which works for factorial() but may not be as workable for other functions.
Answers:
- gmp does better than Gambit-C on bigint multiply, using FFTs.
- breaking the result into two separate functions is needed for C to come ahead.
- yes, C is faster, at the expense of a lot more programming.
- if I want to, I can simply drop C code into my Gambit-C program on an as-needed basis. The Gambit-C code still looks a
whole lot cleaner than the C version, and ties it for small integer performance. The bigint performance is still a "win" for
gmp, but I can use THAT package directly as well in Gambit-C.
Win:
- Gambit-C. The prototype was finished to spec in two minutes. Optim
Just another "Cubible(sic) Joe" 2 17 3061
And now for the grand unveil - the SCHEME (LISP) version, with integrated C code for the "super-speedy" inner loop. Just to illustrate that the SAME optimizations are available for the LISP programmer. This can be further micro-optimized.
Note that it isn't much different from a "C" implementation that has the same optimization. Note the ease of moving between data types (we only worry about in a very cursory way). I am waiting for your pure C implementation.
# In "normal" scheme syntax. Note escape to six syntax (for the C
# developer. Replace [lt] with less-than before compiling
# Define in-line C function for fast factorial within 32 bit constraint
(c-declare #[lt][lt]c-end
int fast_factorial(int n) {
if (n [lt]= 0)
return 1;
return n * fast_factorial(n - 1);
}
c-end
)
(define fast-factorial
(c-lambda (int) int "fast_factorial"))
# The constant 12 is the largest factorial that can be computed in a 32 bit int.
# Notice the function fast-factorial is also escaped: fast-factorial is actually a C expression.
\int factorial(int n) {
if (n [lt]= 12) {
\fast-factorial(n);
} else {
n * factorial(n - 1);
}
}
Just another "Cubible(sic) Joe" 2 17 3061
Today is Memorial Day in the United States of America. We would appreciate you folks taking some time to reflect on our servicemen who gave their lives saving your asses in WW I and II.
Hi, I'm from the country formerly called the Soviet Union. We would appreciate you folks learning your history, so that you'd know that USA wasn't "the country that won WW2". You might, for example, want to remember that over 3/4 of all German losses in manpower were on the Eastern front (5.5 million KIA total, 4.3 out of which are on Eastern front), and that over 10 million Soviet soldiers, and twice as many civilians, payed with their lives for that achievement.
We now come to the final post in this series.
The speed in C comes from the direct hardware "low-level" thing. In the domain of "int" types on a 32 bit machine, I would say that the most efficient (well, one of the most efficient) implementations of factorial() would be:
#define factorial(n) ((n) 0 ? 1 : fact_table[n])
int fact_table[] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 39916800, 479001600 };
Can you hear the l33t-speak? I codez the C r3al g00d! My factorial function only takes a nanosecond or so! And, it ONLY takes two instructions! No, let's do better. We can DOUBLE the speed of this puppy. Just assume that negative numbers will never be passed in.
#define factorial(n) fact_table[n]
That's one fast function now!
This is 32 bit int type only. Not a very interesting or useful case. 64 bits? Brings us to 20! or so. It is certainly a major benefit to Scheme to have the bignum built-in. Have you finished the C version without gmp yet?
Just another "Cubible(sic) Joe" 2 17 3061