Q:

GC interruptions and TPL

I have a WCF service. During the service's work, it needs to call two web services. So there's code similar to this:
var task1 = Task.Factory.StartNew(() => _service1.Run(query));
var task2 = Task.Factory.StartNew(() => _service2.Run(query));
Task.WaitAll(new[] { task1 , task2 });

Most of the time this works OK, but occasionally I was seeing spikes in the execution time, where the first task took a few seconds to even begin. Looking at perfmon, I realized this was exactly when GC was happening. Apparently, GC was a higher priority then running my tasks. This is not acceptable, as latency is very important to me, and I'd prefer GC to happen between requests and not in the middle of a request.
I attempted to go about this a different way, and instead of spinning my own tasks, I used WebClient.DownloadStringTask. 
return webClient.DownloadStringTask(urlWithParmeters).ContinueWith(t => ProcessResponse(clientQuery, t.Result),
                                                                           TaskContinuationOptions.ExecuteSynchronously);

This didn't help; The GC now runs after the task began, but before the continuation. Again, I guess it figured the system is now idle, so it is a good time to begin GC. Only, I can't afford the latency.
Using TaskCreationOptions.LongRunning, which causes the scheduler to use non thread-pool threads, seems to solve this, but I don't want to create so many new threads - this code is going to run a lot (several times per request).
What is the best way to overcome this issue?

A:

Let me first clean up some misunderstandings seen on this page:

GC does not take place when idle. It takes place when triggered due to a failing allocation (new), GC.Collect or OS memory pressure
The GC can stop application threads. It does not run concurrently (at least for a certain amount of time)
"% time in GC" is a counter that does not change between GCs meaning that you might be seeing a stale value
Async code does not help with GC problems. In fact, it generates more garbage (Tasks, IAsyncResult's and probably something else)
Running your code on dedicated threads does not prevent them being stopped

How to fix this?

Generate less garbage. Attach a memory profiler (JetBrains is easy to use) and see what is generating garbage and what is on your heap
Reduce heap size to reduce pause time (A 3GB heap is probably due to some caching? Maybe shrink the cache?)
Start multiple ASP.NET sites with the same app, hook up GC notifications to sense a GC coming and take some of the IIS sites out of load balancing rotation while they are having a GC (http://blogs.msdn.com/b/jclauzel/archive/2009/12/10/gc-notifications-asp-net-server-workloads.aspx?Redirected=true)

You'll notice that there is no easy fix. I don't know one, but if the problem is caused by GC one of the above will fix the problem.

