If it doesn't run fast at first, it will run even slower later.
Here is a quick way to get an idea of how long your request/response takes and a ton of more data regarding your payload.
neXpert is an add-on to Fiddler Web Debugger which aids in performance testing web applications. neXpert was created to reduce the time it takes to look for performance issues with Fiddler and to create a deliverable that can be used to educate development teams.
Blog - http://blogs.msdn.com/nexpert/
Video- http://msdn.microsoft.com/en-us/dd573302.aspx - (4 minutes)
Download -http://www.microsoft.com/downloads/details.aspx?FamilyId=5975DA52-8CE6-48BD-9B3C-756A625024BB&displaylang=en
Introduction - http://blogs.msdn.com/nexpert/archive/2009/02/10/introducing-nexpert.aspx
Deep dive - Nicholas Allen's talk on WCF performance and Scale - PowerPoint Deck - Webcast
From the above talk you get an idea of the pull and the push model and a combination of these for certain channels. This defines how the message will be received on the transport and how they will be dispatched. Consider a pump as a loop doing some work. A pump works off a queue which it would push work on for the next layer or pulls work off when there is some work to be done.
Considering a very common scenario like basic http where a message would arrive on the transport. The flow would consist of 2 loops.
1. Dispatcher gets a message. It has available resources and will dispatch the operation(Application) 2. Dispatcher then tells the pump that it can accept the next message.
1. Pump registers that it can take pull a message. 2. Message arrives and Transport pushes the message to the dispatcher.
All channels affect how messages arrive and how they would be dispatched. We make a fundamental assumption in WCF that channels would always be fast. This is because of the fact that the channel is your infrastructure and it makes sense to put any heavy work to the application layer and not the channel layer.
So general rule of thumb - Do not do blocking or heavy work in your channels. Pass on the work to the upper application layer.
You should think of your channel as gate to your dispatcher and you don't want to block the gate from letting the next person in. Hence bottom line is that a slow channel is a suboptimal channel.
Here is a deep dive on of how to implement your AsyncResult
Quick Pointers
I have a much longer article in mind for this and will be publishing it out soon. But to quickly answer this let us use an implementation from the framework itself using a delegate. Please note, this is for a usage pattern sample only since all that a delegate does is put the work on the CLR's thread pool which means more latency for non-blocking work. ...
Most common data structures are usually meant for single threaded access and queues are no exception. When there are multiple producers writing to the queue we usually need to make sure that the writer is given a unique index that he can put the element into. If our operations are synchronized already and thread safe we can do something like this
public void Enqueue(T item) { ... tail = (tail+1) % size; items[tail] = item; }
public void Enqueue(T item)
{
...
tail = (tail+1) % size;
items[tail] = item;
}
On the other hand if 2 threads simultaneously got to the highlighted line then they could even overwrite each other if the read the value of the tail at the same time. Now what are the issues we face.
We could consider using Interlocked increment and get away with something like this
public void Enqueue(T item) { int next = Interlocked.Increment(ref tail) % size; ... items[next] = item; }
int next = Interlocked.Increment(ref tail) % size;
items[next] = item;
Hmm this doesn't seem right. Well the issue is the wrap around behavior for interlocked.Incremement. Once it reaches Int32.Max value it then gets back to Int32.Min value and then on it's pretty much useless as the next count would read something like (Int32.MinValue%size) wiz quite a an odd value. For example for size 100 we could end up with indexes like this
. 46,47,-48,-49
Lets look at another approach which is CompareExchage. Some fundamentals about Interlocked.CompareExchange
From this we can deduce that if a thread tried to increment a value and failed then someone already updated it. This also means that we might not succeed in a single try and hence would need to retry until till we successfully get a slot which we will own. The fact that we were able to increment it also means that no other thread will get this slot. So now lets look at the implementation.
class LockFreeCircularIterator { int index = 0; readonly int limit; public LockFreeCircularIterator(int limit) { this.limit = limit; } public int GetNext() { int slot = this.index; while(true) { if(slot == (slot = Interlocked.CompareExchange(ref this.index, (slot+1) % limit, slot))) { return slot; } } } }
class LockFreeCircularIterator
int index = 0;
readonly int limit;
public LockFreeCircularIterator(int limit)
this.limit = limit;
public int GetNext()
int slot = this.index;
while(true)
if(slot == (slot = Interlocked.CompareExchange(ref this.index, (slot+1) % limit, slot)))
return slot;
Here we see that we iterate till the index was updated with the incremented value. Each time it failed the new value of the index was read and attempted again. This was one of the implementations of the iterator. This allows multiple threads to write to a circular buffer. I'm omitting the usage as there are quite a few places this could come in hand.
This seemed like a really nice mix of handle.exe from sysinternals and powershell.
Check out the script at http://msgoodies.blogspot.com/2009/03/get-openfile.html
Update fix for get-process piping
You have to remove the '.exe' from the output from handle.exe to get it working to pipe it to gps.
param($fileFilter=$(throw "Filter must be specified")) c:\sysint\handle.exe $fileFilter | foreach { if ($_ -match '^(?<program>\S*)\s*pid: (?<pid>\d*)\s*(?<handle>[\da-z]*):\s*(?<file>(\\\\)|([a-z]:).*)') { $matches | select @{n="Path";e={$_.file}},@{n="Handle";e={$_.handle}},@{n="Pid";e={$_.pid}},@{n="ProcessName";e={$_.Program.Replace(".exe","")}} } }
Bindings (such as BasicHttpBinding, WSHttpBinding etc.) have a have a constructor that take the configuration name. You need to know the type of binding as the name themselves are not unique across different binding sections.
Finally after about 3 releases of WCF we got a configuration service sample on MSDN. I haven't exactly played with the bits myself but did get a good review from some folks who wanted to use it for service management. This does allow a degree of configuration management for your WCF services and I believe can even be backed up to a datastore.
http://msdn.microsoft.com/en-us/netframework/bb499684.aspx
Configuration Service 2.03 is a reusable set of shared libraries that provides central configuration management for .NET applications, ASP.NET Applications, and WCF service hosts. It provides the ability to cluster multiple nodes, with load balancing and application-level failover across remote nodes; as well as a centralized configuration management user interface, cluster and endpoint status monitoring, and dynamic configuration updates across clusters without having to deploy new configuration files or stop/start active nodes. The Configuration Service was born out of a practical need to make it easier to manage the .NET StockTrader composite application in distributed, clustered environments. The concepts were then abstracted such that any .NET application/WCF service host can implement the Configuration Service via the shared libraries provided. This is possible based on the use of base classes and .NET reflection within the shared libraries. For those familiar with WCF, it should only take a few hours to walk through the tutorial and test it out. It is designed such that existing WCF services can easily be integrated into a WCF service host (IIS, Windows Application, Console Application, or Windows NT Service) that implements the Configuration Service.
And yes there is a stock trader application along with it :).