The WaitForAll Roadshow
- by adweigert
OK, so I took for granted some imaginative uses of WaitForAll but lacking that, here is how I am using. First, I have a nice little class called Parallel that allows me to spin together a list of tasks (actions) and then use WaitForAll, so here it is, WaitForAll's 15 minutes of fame ...
First Parallel that allows me to spin together several Action delegates to execute, well in parallel.
public static class Parallel
{
public static ParallelQuery Task(Action action)
{
return new Action[] { action }.AsParallel();
}
public static ParallelQuery> Task(Action action)
{
return new Action[] { action }.AsParallel();
}
public static ParallelQuery Task(this ParallelQuery actions, Action action)
{
var list = new List(actions);
list.Add(action);
return list.AsParallel();
}
public static ParallelQuery> Task(this ParallelQuery> actions, Action action)
{
var list = new List>(actions);
list.Add(action);
return list.AsParallel();
}
}
Next, this is an example usage from an app I'm working on that just is rendering some basic computer information via WMI and performance counters. The WMI calls can be expensive given the distance and link speed of some of the computers it will be trying to communicate with. This is the actual MVC action from my controller to return the data for an individual computer.
public PartialViewResult Detail(string computerName)
{
var computer = this.Computers.Get(computerName);
var perf = Factory.GetInstance();
var detail = new ComputerDetailViewModel()
{
Computer = computer
};
try
{
var work = Parallel
.Task(delegate
{
// Win32_ComputerSystem
var key = computer.Name + "_Win32_ComputerSystem";
var system = this.Cache.Get(key);
if (system == null)
{
using (var impersonation = computer.ImpersonateElevatedIdentity())
{
system = computer.GetWmiContext().GetInstances().Single();
}
this.Cache.Set(key, system);
}
detail.TotalMemory = system.TotalPhysicalMemory;
detail.Manufacturer = system.Manufacturer;
detail.Model = system.Model;
detail.NumberOfProcessors = system.NumberOfProcessors;
})
.Task(delegate
{
// Win32_OperatingSystem
var key = computer.Name + "_Win32_OperatingSystem";
var os = this.Cache.Get(key);
if (os == null)
{
using (var impersonation = computer.ImpersonateElevatedIdentity())
{
os = computer.GetWmiContext().GetInstances().Single();
}
this.Cache.Set(key, os);
}
detail.OperatingSystem = os.Caption;
detail.OSVersion = os.Version;
})
// Performance Counters
.Task(delegate
{
using (var impersonation = computer.ImpersonateElevatedIdentity())
{
detail.AvailableBytes = perf.GetSample(computer, "Memory", "Available Bytes");
}
})
.Task(delegate
{
using (var impersonation = computer.ImpersonateElevatedIdentity())
{
detail.TotalProcessorUtilization = perf.GetValue(computer, "Processor", "% Processor Time", "_Total");
}
}).WithExecutionMode(ParallelExecutionMode.ForceParallelism);
if (!work.WaitForAll(TimeSpan.FromSeconds(15), task => task()))
{
return PartialView("Timeout");
}
}
catch (Exception ex)
{
this.LogException(ex);
return PartialView("Error.ascx");
}
return PartialView(detail);
}