Wednesday, February 17, 2010

Blazing fast IPC in .Net 4: WCF vs. Signaling and Shared Memory

[Update 2011-02-02: Did a test against NamedPipeServerStream and NamedPipeClientStream which i mention in a comment at the end]

An MSDN article from 2007 compares the speed of WCF vs. .Net Remoting, and shows the speed increase WCF gives over remoting in an IPC scenario using named pipes as transport. With the introduction of the System.IO.MemoryMappedFiles namespace in .Net 4 and a blog post by Salva Patuel which outlines that almost all communication inside windows uses memory mapped files at it’s core, I had to try this myself with the new capabilities in the .Net 4 framework.

My approach implements messaging between two processes by writing the data to a memory mapped file (which essentially is shared memory), and signaling between the processes using an EventWaitHandle object. One process signals when the data is written, and the other when it has been processed.

While WCF converge towards the speed of .Net Remoting when the payload increases, the memory mapped approach with signaling is consistent with being 10x as fast as WCF for all three payload sizes. With a payload of 256k bytes I get a throughput of 4000 ops/sec on my 2.2ghz laptop with a 800mhz FSB.
The process receiving handling the reading can be incorporated like this:

var message = new byte[..];
var messageWait = new EventWaitHandle(false, EventResetMode.AutoReset, "wait");
var messageHandled = new EventWaitHandle(false, EventResetMode.AutoReset, "handled");
var mmf = MemoryMappedFile.CreateOrOpen("mmf", message.Length);
var viewStream = mmf.CreateViewStream();

while (!_quit)
if (_quit) break;               
viewStream.Position = 0;
viewStream.Read(message, 0, message.Length);
// handle the message
//dispose of objects

You would write similar code for the other process, changing the order of the wait handles.

So by using a fairly simple pattern and little code you can achieve blazing fast communication between two or more processes on the same machine.

Other obvious usages for memory mapped files are random access into large files due to the files being paged smartly. Particularly check out MemoryMappedFile.CreateViewAccessor() for an easy way to access value types individually or in an array.