Want more features on Pastebin? Sign Up, it's FREE!
Guest

Dan Tao

By: a guest on Jan 24th, 2011  |  syntax: C#  |  size: 6.22 KB  |  views: 409  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Linq;
  6. using System.Threading;
  7. using System.Threading.Tasks;
  8.  
  9. namespace ConcurrentBagTest
  10. {
  11.     class Program
  12.     {
  13.         static void Main(string[] args)
  14.         {
  15.             var listTester = new LockedListTester();
  16.             var bagTester = new ConcurrentBagTester();
  17.  
  18.             do
  19.             {
  20.                 try
  21.                 {
  22.                     int collectionSize = GetNumber("Collection size");
  23.                     int readerThreadCount = GetNumber("Number of reader threads to create");
  24.                     int trialCount = GetNumber("Number of trials to run");
  25.  
  26.                     TimeSpan totalListTime = TimeSpan.Zero, totalBagTime = TimeSpan.Zero;
  27.  
  28.                     for (int i = 0; i < trialCount; ++i)
  29.                     {
  30.                         TimeSpan listTime = listTester.TestSimultaneousReadsWrites(collectionSize, readerThreadCount);
  31.                         TimeSpan bagTime = bagTester.TestSimultaneousReadsWrites(collectionSize, readerThreadCount);
  32.  
  33.                         totalListTime += listTime;
  34.                         totalBagTime += bagTime;
  35.  
  36.                         Console.WriteLine("Took {0} ms to add {1} elements to a List<double> with {2} reader threads.", listTime.TotalMilliseconds, collectionSize, readerThreadCount);
  37.                         Console.WriteLine("Took {0} ms to add {1} elements to a ConcurrentBag<double> with {2} reader threads.", bagTime.TotalMilliseconds, collectionSize, readerThreadCount);
  38.                     }
  39.  
  40.                     Console.WriteLine("Average list time: {0} ms.", totalListTime.TotalMilliseconds / trialCount);
  41.                     Console.WriteLine("Average bag time: {0} ms.", totalBagTime.TotalMilliseconds / trialCount);
  42.                 }
  43.                 finally
  44.                 {
  45.                     Console.Write("Go again? ");
  46.                 }
  47.             }
  48.             while (Console.ReadLine().StartsWith("y", StringComparison.OrdinalIgnoreCase));
  49.         }
  50.  
  51.         static int GetNumber(string prompt)
  52.         {
  53.             Console.Write("{0}: ", prompt.TrimEnd(':', ' '));
  54.  
  55.             int input;
  56.             while (!int.TryParse(Console.ReadLine(), out input))
  57.             {
  58.                 Console.Write("That was not a valid number--try again: ");
  59.             }
  60.  
  61.             return input;
  62.         }
  63.     }
  64.  
  65.     abstract class ConcurrentCollectionTester<T, TCollection>
  66.     {
  67.         public TimeSpan TestSimultaneousReadsWrites(int collectionSize, int readerThreadCount)
  68.         {
  69.             // Keep the playing field even.
  70.             GC.Collect();
  71.  
  72.             TCollection collection = CreateCollection(collectionSize);
  73.  
  74.             var threads = new Thread[readerThreadCount];
  75.             using (var stopReaders = new ManualResetEvent(false))
  76.             {
  77.                 int readersFinished = 0;
  78.  
  79.                 // Spin off a bunch of reader threads continuously enumerating
  80.                 // over the collection.
  81.                 for (int i = 0; i < threads.Length; ++i)
  82.                 {
  83.                     threads[i] = new Thread(() =>
  84.                     {
  85.                         while (!stopReaders.WaitOne(0))
  86.                         {
  87.                             EnumerateCollection(collection);
  88.                         }
  89.                         Interlocked.Increment(ref readersFinished);
  90.                     }
  91.                     );
  92.  
  93.                     threads[i].Start();
  94.                 }
  95.  
  96.                 // Now see how long it takes to populate the collection while
  97.                 // all those readers are going.
  98.                 Stopwatch stopwatch = Stopwatch.StartNew();
  99.                 Parallel.For(0, collectionSize, i =>
  100.                 {
  101.                     T element = CreateElement(i);
  102.                     AddToCollection(collection, element);
  103.                 }
  104.                 );
  105.                 stopwatch.Stop();
  106.  
  107.                 // Signal that the readers can stop.
  108.                 stopReaders.Set();
  109.  
  110.                 // Wait for the last reader to finish (not really relevant to
  111.                 // this test--just needed to avoid a race condition that would
  112.                 // throw an ObjectDisposedException on the WaitHandle).
  113.                 SpinWait.SpinUntil(() => readersFinished == readerThreadCount);
  114.  
  115.                 return stopwatch.Elapsed;
  116.             }
  117.         }
  118.  
  119.         protected virtual TCollection CreateCollection(int collectionSize)
  120.         {
  121.             return Activator.CreateInstance<TCollection>();
  122.         }
  123.  
  124.         protected abstract void AddToCollection(TCollection collection, T item);
  125.  
  126.         protected abstract void EnumerateCollection(TCollection collection);
  127.  
  128.         protected abstract T CreateElement(int index);
  129.     }
  130.  
  131.     sealed class LockedListTester : ConcurrentCollectionTester<double, List<double>>
  132.     {
  133.         // For writes/reads to/from a List<T> to be safe, we'll need to lock
  134.         // both.
  135.         private object m_lock = new object();
  136.  
  137.         protected override void AddToCollection(List<double> collection, double item)
  138.         {
  139.             lock (m_lock)
  140.             {
  141.                 collection.Add(item);
  142.             }
  143.         }
  144.  
  145.         protected override void EnumerateCollection(List<double> collection)
  146.         {
  147.             lock (m_lock)
  148.             {
  149.                 double sum = collection.Sum();
  150.             }
  151.         }
  152.  
  153.         protected override double CreateElement(int index)
  154.         {
  155.             return (double)index;
  156.         }
  157.     }
  158.  
  159.     sealed class ConcurrentBagTester : ConcurrentCollectionTester<double, ConcurrentBag<double>>
  160.     {
  161.         // A ConcurrentBag<T> is supposed to be thread-safe with no need for
  162.         // any locking.
  163.  
  164.         protected override void AddToCollection(ConcurrentBag<double> collection, double item)
  165.         {
  166.             collection.Add(item);
  167.         }
  168.  
  169.         protected override void EnumerateCollection(ConcurrentBag<double> collection)
  170.         {
  171.             double sum = collection.Sum();
  172.         }
  173.  
  174.         protected override double CreateElement(int index)
  175.         {
  176.             return (double)index;
  177.         }
  178.     }
  179. }
clone this paste RAW Paste Data