Sascha is correct about thread safety.
However, if you are using the
.AsParallel()
to improve performance, you're going about it incorrectly!
Since
bg
is a
List<string>
, the
.Contains()
is a very poor way to check for membership in the list. It is
O(n) (where
n is
bg.Length
). So the overall query is
O(n*m) (where
m is
UE.Count
).
Instead, you should make a
HashSet<string>
from
bg
and check for membership in the set.
That is
O(1), making the overall query directly proportional to
UE.Count
.
Using the
HashSet
is about
100 times faster (on my system) than the parallelized scan of
bg
.
Parallelizing the HashSet version
actually slows it down, presumably due to the parallelization setup and context switching and coordination overhead.
Here's my testing code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace ConsoleApplication10
{
class Program
{
static void Main(string[] args)
{
Random rand = new Random();
Stopwatch swp = new Stopwatch();
Stopwatch swh = new Stopwatch();
Stopwatch swph = new Stopwatch();
bool tail = false;
const int count = 200;
for (int i = 0; i <= count; i++)
{
Dictionary<string, int> UE = new Dictionary<string, int>();
List<string> bg = new List<string>();
int roff = rand.Next(1000);
foreach (var item in Enumerable.Range(roff, 10000))
{
string key = item.ToString("D");
UE.Add(key, item % (roff + 500));
if (item % 10 == 0)
bg.Add(key);
}
if (tail)
swp.Start();
List<int> tp = UE.AsParallel().Where(x => bg.Contains(x.Key, StringComparer.OrdinalIgnoreCase)).Select(y => y.Value).Distinct().ToList();
if (tail)
swp.Stop();
if (tail)
swh.Start();
HashSet<string> hs = new HashSet<string>(bg, StringComparer.OrdinalIgnoreCase);
List<int> th = UE.Where(x => hs.Contains(x.Key)).Select(y => y.Value).Distinct().ToList();
if (tail)
swh.Stop();
if (tail)
swph.Start();
HashSet<string> hps = new HashSet<string>(bg, StringComparer.OrdinalIgnoreCase);
List<int> tph = UE.AsParallel().Where(x => hps.Contains(x.Key)).Select(y => y.Value).Distinct().ToList();
if (tail)
swph.Stop();
tail = true;
UE = null;
bg = null;
hs = null;
hps = null;
GC.Collect();
}
Console.WriteLine("Parallel processing: {0:F2} ticks (avg)", swp.ElapsedTicks / (double)count);
Console.WriteLine("HashSet processing: {0:F2} ticks (avg)", swh.ElapsedTicks / (double)count);
Console.WriteLine("Parallel & HashSet processing: {0:F2} ticks (avg)", swph.ElapsedTicks / (double)count);
Console.WriteLine("Return to exit");
Console.ReadLine();
}
}
}