Node.cs
No, the title is not a typo. There is so much noise around Node.js, I thought it would be fun to make a sample of how it would work in C# using the TPL. Here is how the hello world sample would look like:
public class HelloHandler : AbstractAsyncHandler { protected override Task ProcessRequestAsync(HttpContext context) { context.Response.ContentType = "text/plain"; return context.Response.Output.WriteAsync("Hello World!"); } }
And the code to make this happen:
public abstract class AbstractAsyncHandler : IHttpAsyncHandler { protected abstract Task ProcessRequestAsync(HttpContext context); private Task ProcessRequestAsync(HttpContext context, AsyncCallback cb) { return ProcessRequestAsync(context) .ContinueWith(task => cb(task)); } public void ProcessRequest(HttpContext context) { ProcessRequestAsync(context).Wait(); } public bool IsReusable { get { return true; } } public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) { return ProcessRequestAsync(context, cb); } public void EndProcessRequest(IAsyncResult result) { if (result == null) return; ((Task)result).Dispose(); } }
And you are pretty much done. I combined this with a HttpHandlerFactory which does the routing, and you get fully async, and quite beautiful code.
Comments
Ayende, have You seen this https://gist.github.com/1097383 from @thinkbeforecoding?
Yes, it's very easy to write async web handlers in .net, either using HttpHandlers or the HttpListener (Nancy has both), but it's still using the threadpool, and thread per request, so hardly the same thing as node's event loop.
I don't see how this compares to node.js at all.
it's not the same at all IIRC node on Windows uses IOCP, but TPL uses ThreadPool.
Where's the rest of the code?
p.s. node.cs is already underway https://github.com/Rduerden/Node.cs
Also worth checking out http://nuget.org/List/Packages/SignalR - uses async and await for coding within ASP.NET MVC
.NET also uses IOCP underneath, but the events are executed on the default thread pool.
There is also this one (HttpListener + Rx) for Commet style :
https://gist.github.com/1097515
By the way, using Rx doesn't block threads. Only the HttpListenerContext object is kept in memory between request. And you can schedule request handling on your preferred scheduler (Tasks, ThreadPool, new thread... custom ?)
Have you seen this implementation made by Jose Romaniello ?
http://joseoncode.com/2011/06/17/event-driven-http-server-in-c-with-rx-and-httplistener/
He built an event driven http server using Rx.
Victor, No, I didn't. I don't like the sync write there, but seems to be in the same vein
Steven, Actually, no. This will not be using the thread pool to wait, it is using overlapped IO, so there is no thread waiting around for this. This is actually quite similar
Sergey, Async operations uses overlapped io, and this uses a thread pool thread only when it is executing your code, not when waiting for anything.
Thilak, My only interest was to show how it can be done, not to actually implement another framework
Actually the write is not sync with the request in the first gist. It's already scheduled on the Task pool.
I didn't say your code was using the threadpool,but asp.net will still use threadpool threads to handle the initial connection/request, and after you've finished your async work to send the response. This is different to the single threaded event loop/scheduler that node uses.
Something like Kayak (https://github.com/kayak/kayak) is closer to the node model.
Ok for the event loop.. but what is the advantage of using it ?
@thinkbeforecoding
You can read second paragraph from here http://nodejs.org/#about
And not a word about Manos?
since manos really use the same libev thing that powers node.js it is actually comparable both in perf and paradigm. You lose the node.js ecosystem (mainly npm) but gain the BCL (with almost every IO thing supporting async)
@alex in that case you can use a loop based scheduler like the Wpf dispatcher or any custom and simple implementation
I really like to rub this code into node.js's followers. This stupid fad with node.js kind of makes me angry because I don't understand why even programmers fall for fashion so easily.
"less-than-expert programmers are able to develop fast systems": Well, try to get non-expert users to write code that whose guts have been pulled inside out (callback instead of pull-model).
It makes me angry how useless node.js is. It is outright harmful to use it.
Wow tobi. You need to get out more. Please explain how using less memory and non-blocking services is harmful? Are you one of those types that only learn new technology if your company pays for training?
Programmers fall for fashion because it is entirely possible that today's fashion might lead to tomorrow's job. The more diverse your skillet is, the more opportunities you have to do something interesting.
Perhaps you should run a benchmark against node and .net and prove that node is harmful.
I think there's a fascination with node.js because programmers get tired of doing the same old applications.
Dev: I'm writing a CMS/CRM/Project Management/etc Fanboi dev: Booooring! Dev: I'm doing it with node .js Fanboi dev: Oh wow cool!
Jack, you rarely need the 10% in throughput you get from async IO. Most of the time you need developer productivity. See my comment about turning the code inside out. I have written async code myself. It is a terrible exercise. Did you ever writecode that did async IO in a loop? Can't use a while loop cause the function has to exit after every IO...
Remember, performance vs. productivity. Bad trade-off to choose performance most of the time.
Ayende, is it possible to estimate memory footprint of node.js and .net async handler for, lets say, 200 simultaneously connected users?
dkl, Without actually running load tests? Not really, I don't expect that to be too high, mind.
"I really like to rub this code into node.js's followers. "
Wow, you sound incredibly sad. There are a lot of defensive MS-stack programmers leaving comments here.
John, the right to flame has to be earned. I did earn it with my reasoning about node.js. Feel free to answer my points, then you are allowed to flame.
@tobi: The IO facilities in Node let you get all the data at once, in a single callback, or let you use a 'stream', which is basically an event dispatcher that delivers the chunked payloads of the async file reads.
From what I have seen, Node.js makes heavy use of the continuation-passing style (CPS) of programming, which has been prevalent in Lisps (or at least in their compilers) for a great, long while, and allows for tail-call optimizations pretty much everywhere.
And while I agree that to most it looks strange, it makes sense for Node use this style, since JavaScript is a functional programming language. I would imagine that a similar style could easily be written in F# (or even C# with great, heaping piles of Func<> and Action<>), although I admit I am very unfamiliar with F#.
(see also: static single assignment (SSA) and automatic conversion to CPS)
Chris, all of what you say is true. You did not make a statement that contradicts what I have said.
I want to address your "streaming" point: Streaming is most useful if the payload is too large to fit in memory. This is a very unusual case. ASP.NET allows for full streaming, though, if you want to. You can even do it asynchronously.
Remember, I fully acknowledge the potential performance improvements of async IO. I just say it is a terrible tradeoff in 99% of all applications. I really mean this number literally. When did you last need async IO? I never did (I implemented it for fun however, so I know what I am talking about).
"I would imagine that a similar style could easily be written in F#": Yes, async worflows are made for exactly that. They are far superior to javascripts CPS. In C# 5 a similar feature will be introduced which will make using node.js not just unwise, but totally absurd.
Is node.js just asynchrony?
I think it is cool that you can write server side code in Javascript with no context switching between 2 different languages for client & server side code. Maybe there are libraries out there that blur the distinction further, have not researched...
Putting together V8 with async IO is pure genius. Just like Ayende combined a little known Esent library with Lucene.net and got RavenDB.
.NET came with great support for asynchrony even back in the 1.1 days (I personally have used the AsyncPage library from DevelopMentor years back) uses same IAsyncHttpHandler plumbing in this post.
But to get async IO support into languages/frameworks as node.js & Python Torando does is still awesome!
Ajai
I would see the point in having node.js with synchroneous IO. This does not preclude concurrency at all (it does not do this in any other synchroneous programming environment either).
@tobi And what is the point to block event loop for synchroneous IO ?
There would be no event loop. It would be a plain old server. The point would be to get node.js's other benefits like using the same language on the server and client.
@tobi
re: "When did you last need async IO? I never did (I implemented it for fun however, so I know what I am talking about)."
Perhaps you should write more successful code. Working in an industry where millions of requests, large web farms, caching at the edge and everywhere in between serving out millions of requests an hour I can tell you there are many great solutions for async IO and I have implemented it so I know what I am talking about.
You can have your opinions, just dont presume they are more correct than anyone elses.
Great stuff! Here's a similar one also: https://github.com/SignalR/SignalR/blob/master/SignalR/Web/HttpTaskAsyncHandler.cs
Cool, but the problem with C# is its ugly. This is a lot harder to read than a node.js program.
Robert, I actually disagree with you here. I think it is as easy or easier. It just require practice
Comment preview