Parallel.For vs BackgroundWorker

A number of jobs I get are fairly processor intensive so I decided to take a look at .Net’s new Parallel library, wondering how performant it’d be in my (not necessarly your) environment. Implementation is fairly straightforward, with a minor lambda expression.

My busy routine copies an array to a SQL server. The array is 8 columns by 10,000 rows. The columns are strings, each column has it’s own sql table, I ‘normalize’ these columns first. Each column ‘normalization’ being a seperate process.

The SQL server is on the same machine as the running application. (i7-2670M,8GB,SSD,Win7 on VMWare Workstation)

Speed. (Times are an average of five runs)
// Single threaded: Normalization time: 00:03:33.33
// Background worker (5 async threads): Normalization time: 00:02:31.39
// 4 processors, Parallel: Normalization time: 00:03:15.30
// 2 processors, Parallel: Normalization time: 00:04:05.59

Suprisingly, the Parallel.For library was significantly slower (24%) than BGW on a four processor machine. CPU utilization did not exceed 41% for any of the tests. It looks like the extra abstraction layer, whereas convinient, adds a fair amount of time to the tests.

Stopwatch stopWatch = new Stopwatch();

//// Single threaded
//// Normalization time: 00:03:33.33
//NormalizeColumn(new NormalizationState(2, "Name", false));
//NormalizeColumn(new NormalizationState(3, "Voltage", true));
//NormalizeColumn(new NormalizationState(4, "Equipment", true));
//NormalizeColumn(new NormalizationState(5, "Type", true));
//NormalizeColumn(new NormalizationState(6, "Zone", true));

//// Background worker
//// Normalization time: 00:02:31.39
//bwThreadCount = 0;
//foreach (BackgroundWorker w in bw)
//    w.WorkerReportsProgress = false;
//    w.WorkerSupportsCancellation = false;
//    w.DoWork += new DoWorkEventHandler(BusyWork);
//    w.RunWorkerAsync(new NormalizationState(bwThreadCount + 2, names[bwThreadCount], states[bwThreadCount]));
//    bwThreadCount++;
//    Thread.Sleep(100);
//while (bwThreadCount > 0) Thread.Sleep(15000);

// 4 processors, Parallel
// Normalization time: 00:03:15.30
// 2 processors, Parallel
// Normalization time: 00:04:05.59
Parallel.For(2, 7, p =>
    switch (p)
        case 2: NormalizeColumn(new NormalizationState(2, "Name", false)); break;
        case 3: NormalizeColumn(new NormalizationState(3, "Voltage", true)); break;
        case 4: NormalizeColumn(new NormalizationState(4, "Equipment", true)); break;
        case 5: NormalizeColumn(new NormalizationState(5, "Type", true)); break;
        case 6: NormalizeColumn(new NormalizationState(6, "Zone", true)); break;

TimeSpan ts = stopWatch.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
Console.WriteLine(" Normalization time: " + elapsedTime);

Leave a Reply