Simple web server benchmark - vibe.d is slower than node.js and Go?

bitwise bitwise.pvt at gmail.com
Sun Sep 24 16:05:16 UTC 2017


On Sunday, 24 September 2017 at 08:08:35 UTC, Petar Kirov 
[ZombineDev] wrote:
> On Saturday, 23 September 2017 at 22:07:58 UTC, bitwise wrote:
>>
>> [...]
>
> Can you give a bit more details? What kind of architectures do 
> you mean (hardware, software, ..)?
> What was your use case? IO-multiplexing, coarse-grained 
> high-level cooperative multi-tasking, or range-like data 
> processing state-machines?

Probably not without embarrassing myself ;)
Even now, server tech isn't really my domain, and it was a long 
time ago.

The effort was mainly a learning experience to better understand 
what's going on under the hood when working on multiplayer games, 
web-apps, etc..

All of my implementations were built around the same code though, 
except request scheduling, where I first tried some kind of state 
machine, and then switched to fibers afterward, which totally 
destroyed it's already mediocre performance.

> Very interesting, I would like to hear more about your 
> approach. I have kind of the opposite experience with C# v7.1. 
> When writing synchronous pull-style code I constantly miss the 
> power of D's ranges

I'm not talking about using IEnumerators as generators. I mean 
using them for user-level threads. So basically, an IEnumerator 
method being "ticked" regularly by a scheduler/engine could 
return a scalar or predicate that specified when execution should 
resume, or it could return another IEnumerator method that the 
scheduler would run to completion before returning to the first 
one.

Simplified pseudo-example:

`
IEnumerator Attack(enemy) {
     // attack until enemy dead or escaped
     // maybe the enemy parameter should be 'scope' XD
}

IEnumerator Idle() {
     enemy = null;

     while(true) {
         position += wanderOffset();

         if(enemy = getEnemiesInRange()) {
             yield Attack(enemy);
             enemy = null;
             yield 2.seconds;
         }

         yield;
     }
}

engine.runCoroutine(Idle());

while(true) { // 60 FPS+
     engine.tickCoroutines();
     // ...
     engine.draw();
}
`

I think it's easy to imagine how using fibers would be much more 
expensive in the above example as it scales in number of AI 
characters and complexity of behavior.

> About push-style asynchronous code, I find async/await unusable 
> for anything more than the absolute basic stuff. For 95% of my 
> code in this area I use RX.NET (http://reactivex.io/). I'm sure 
> they probably use async/await somewhere down in their 
> implementation, but I just find that it scales very poorly when 
> complexity increases.
> My time "lost" by going from Task<T> to IObservable<T> (yes, 
> even for single items) is immediately regained by using a few 
> powerful operators like Buffer, CombineLatest and Switch.

I'm not sure I understand exactly what you're talking about here, 
but I know that basic applications get A LOT easier with 
async/await. For GUI-based applications with network 
connectivity, the whole concept of threading basically 
disappears. No need for locks, no need to dispatch UI updates to 
the main thread. Just code naturally and expect functions that 
make network calls to just take as long as they need without ever 
blocking the UI thread.

As far as using async/await at scale, I would blame C# and it's 
standard library before than the underlying concept itself. I 
don't think there's anything inherently slow about an async/await 
type framework, but if you look at microsoft's reference source 
for C# online, you can see that it's designed with productivity 
in mind, and that performance takes a back seat. I'm sure the 
situation in C++ will be very different if stackless resumables 
are accepted.



More information about the Digitalmars-d mailing list