Monday, May 7, 2012

A .NET Rx Driven Web Server

Edit: please see my other post on creating a .NET Web Server from Rx (Reactive Extensions) since it contains better code.

Although I've seen .Net Rx (Reactive Extensions) around, I never messed with them until today. To me, the concepts behind Rx always seemed self explanatory--perhaps because i have accomplished concurrent apps in .NET 1.0/2.0 without them. However, having spent a little time with them today, I think Rx is good stuff. Honestly, I'm impressed with the interfaces and the services they provide. Let's check it out:

What are the .Net Reactive Extensions(Rx)?

Short answer: pubsub.

Long answer: a ton of sugar over top of .Net streams, async, TPL, and pubsub. I'm not going to get into the generic intros you can find elsewhere that involve streaming enumerables to the console. Instead I'd prefer to create the argument for Rx as such-- when given the need for "X", it is better to provide "the ability to provide X" than "X" itself. The Reactive Extensions give you a ton of really helpful methods to aide you in implementing "the ability to create X" over "X" itself. Allow me to explain--

If i asked you to write me a function that gave me the first 1 million numbers, how would you implement it? I know a younger me would've started on cranking out a for loop, not taking into consideration that decision's implications upon the system's memory. A smarter implementation would be to give me a function/object that gives me the ability to create the first million numbers, perhaps through iterating through the set. Such an object could then forgo the previously mentioned memory issues. The idea of giving "the ability to create/observe X" over "X" itself is arguably the conceptual basis of functional programming's lazy evaluation, which is also what Rx aims to help the user create (to me, at least). So, out of the box you get a ton of ways to create and enable the push/pull of streaming data and/or events.

An Rx TCP Server

The first thing i could think of to make with Rx is a single-threaded TCP server. Maybe that's because when i think of streaming data these days, i tend to think of a node.js style web server. How hard could it be? (And what would the performance be like...?

Version One: A Single-Threaded Non-Rx Readonly TCP Server

If you run the following code, and make a request on your web browser to http://localhost:8081 you'll see the GET request come through to the app.

Version Two: A Single-Threaded Rx Enabled TCP Server

In this version I added two properties to the NetActor-- Incoming and Outgoing. Both are based on new Rx interfaces that allow the client to tap into the push/pull of data to the client. So if you open your web browser, open up the localhost site, and then type into the console app and press enter, it will get delivered to the web page:

Version Three: The Node.js Killer

Ok, so in order to get apache bench to recognize my console app as a web server i had to bind the NetActor's Ip to something other than localhost... not sure why. Once i got that working, i had intermittent failure until I implemented part of the HTTP spec-- at least the response code and connection closed. After that, and also after creating the ability for the NetActor to shut itself down and start itself up, here is what i was left with:

Apache Bench Results

At 500ms+ with a concurrency level of 1, this is definitely not a node.js killer..... ;-)

No comments:

Post a Comment