Thank you for sharing your numbers! I’ll focus on the largest change I see: Nala Ginrut writes: > -c 1000 > art work -s guile > ---------------- > Thread Stats Avg Stdev Max +/- Stdev > Latency 203.02ms 121.22ms 1.90s 59.75% > art work -s fibers > -------------------- > Thread Stats Avg Stdev Max +/- Stdev > Latency 613.76ms 79.96ms 666.43ms 95.09% > art work -s ragnarok; single instance > -------------------- > Thread Stats Avg Stdev Max +/- Stdev > Latency 284.85ms 515.70ms 1.97s 82.14% You can see the systems cope differently with overload. Ragnarok and pristine Guile both let specific requests starve, while fibers accepts higher average latency to avoid high maximum latency. Is this repeatable? If yes, then you can see the difference in scheduling here: With fibers none of the 1000 requests has to wait more than a second, while with pristine guile and with ragnarok some requests can stall everything. If you have a lot of resources being loaded to display a page, the maximum latency is the effective page load delay. I left out the 4-instance ragnarok test, because its coping with latency in the face of overload is not comparable, since it is less highly overloaded (and that’s the feature which struck me while reading). And anyway: These are already pretty good numbers. They don’t achieve the level of static file serving with massive caching (in my tests lighttpd could get more than a factor 2 increase over (fibers web server)), but it’s already on a level where it could support around 500 active users on a single instance running on consumer hardware. As reference the following are results when I test plain guile fibers vs. lighttpd (the "it works" page) against my home server in my local network: Guile (fibers web server) ------------------------- wrk -c 100 -t 4 -d 10 4 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 138.76ms 46.83ms 318.43ms 80.22% Req/Sec 183.58 35.46 261.00 75.27% 7401 requests in 10.00s, 664.93KB read Requests/sec: 740.02 Transfer/sec: 66.49KB wrk -c 1000 -t 4 -d 10 4 threads and 1000 connections Thread Stats Avg Stdev Max +/- Stdev Latency 1.45s 685.52ms 4.08s 84.22% Req/Sec 144.65 41.90 248.00 72.22% 5768 requests in 10.03s, 518.22KB read Socket errors: connect 0, read 33, write 0, timeout 472 Requests/sec: 575.29 Transfer/sec: 51.69KB (for the 1000 connections, I had to use ulimit -n 24000 as root to avoid a "too many open files" error) Lighttpd -------- wrk -c 100 -t 4 -d 10 4 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 65.60ms 43.02ms 416.93ms 78.83% Req/Sec 372.27 49.61 523.00 73.79% 14755 requests in 10.00s, 4.96MB read Requests/sec: 1475.31 Transfer/sec: 508.31KB wrk -c 1000 -t 4 -d 10 http://d6.gnutella2.info 4 threads and 1000 connections Thread Stats Avg Stdev Max +/- Stdev Latency 129.14ms 145.20ms 1.56s 88.33% Req/Sec 372.59 140.95 728.00 60.26% 14830 requests in 10.01s, 4.99MB read Socket errors: connect 0, read 4, write 0, timeout 3074 Requests/sec: 1481.89 Transfer/sec: 510.59KB The Guile web server is just this: (import (fibers web server)) (define (handler request body) (values '((content-type . (text/plain))) "Hello World!\n")) (run-server handler #:addr INADDR_ANY #:port 1234) What I also see is that Artanis seems to have low overhead. How do the numbers change with more complex pages? Best wishes, Arne