Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Linq;
- using System.Threading;
- using System.Threading.Tasks;
- namespace ConcurrentBagTest
- {
- class Program
- {
- static void Main(string[] args)
- {
- var listTester = new LockedListTester();
- var bagTester = new ConcurrentBagTester();
- do
- {
- try
- {
- int collectionSize = GetNumber("Collection size");
- int readerThreadCount = GetNumber("Number of reader threads to create");
- int trialCount = GetNumber("Number of trials to run");
- TimeSpan totalListTime = TimeSpan.Zero, totalBagTime = TimeSpan.Zero;
- for (int i = 0; i < trialCount; ++i)
- {
- TimeSpan listTime = listTester.TestSimultaneousReadsWrites(collectionSize, readerThreadCount);
- TimeSpan bagTime = bagTester.TestSimultaneousReadsWrites(collectionSize, readerThreadCount);
- totalListTime += listTime;
- totalBagTime += bagTime;
- Console.WriteLine("Took {0} ms to add {1} elements to a List<double> with {2} reader threads.", listTime.TotalMilliseconds, collectionSize, readerThreadCount);
- Console.WriteLine("Took {0} ms to add {1} elements to a ConcurrentBag<double> with {2} reader threads.", bagTime.TotalMilliseconds, collectionSize, readerThreadCount);
- }
- Console.WriteLine("Average list time: {0} ms.", totalListTime.TotalMilliseconds / trialCount);
- Console.WriteLine("Average bag time: {0} ms.", totalBagTime.TotalMilliseconds / trialCount);
- }
- finally
- {
- Console.Write("Go again? ");
- }
- }
- while (Console.ReadLine().StartsWith("y", StringComparison.OrdinalIgnoreCase));
- }
- static int GetNumber(string prompt)
- {
- Console.Write("{0}: ", prompt.TrimEnd(':', ' '));
- int input;
- while (!int.TryParse(Console.ReadLine(), out input))
- {
- Console.Write("That was not a valid number--try again: ");
- }
- return input;
- }
- }
- abstract class ConcurrentCollectionTester<T, TCollection>
- {
- public TimeSpan TestSimultaneousReadsWrites(int collectionSize, int readerThreadCount)
- {
- // Keep the playing field even.
- GC.Collect();
- TCollection collection = CreateCollection(collectionSize);
- var threads = new Thread[readerThreadCount];
- using (var stopReaders = new ManualResetEvent(false))
- {
- int readersFinished = 0;
- // Spin off a bunch of reader threads continuously enumerating
- // over the collection.
- for (int i = 0; i < threads.Length; ++i)
- {
- threads[i] = new Thread(() =>
- {
- while (!stopReaders.WaitOne(0))
- {
- EnumerateCollection(collection);
- }
- Interlocked.Increment(ref readersFinished);
- }
- );
- threads[i].Start();
- }
- // Now see how long it takes to populate the collection while
- // all those readers are going.
- Stopwatch stopwatch = Stopwatch.StartNew();
- Parallel.For(0, collectionSize, i =>
- {
- T element = CreateElement(i);
- AddToCollection(collection, element);
- }
- );
- stopwatch.Stop();
- // Signal that the readers can stop.
- stopReaders.Set();
- // Wait for the last reader to finish (not really relevant to
- // this test--just needed to avoid a race condition that would
- // throw an ObjectDisposedException on the WaitHandle).
- SpinWait.SpinUntil(() => readersFinished == readerThreadCount);
- return stopwatch.Elapsed;
- }
- }
- protected virtual TCollection CreateCollection(int collectionSize)
- {
- return Activator.CreateInstance<TCollection>();
- }
- protected abstract void AddToCollection(TCollection collection, T item);
- protected abstract void EnumerateCollection(TCollection collection);
- protected abstract T CreateElement(int index);
- }
- sealed class LockedListTester : ConcurrentCollectionTester<double, List<double>>
- {
- // For writes/reads to/from a List<T> to be safe, we'll need to lock
- // both.
- private object m_lock = new object();
- protected override void AddToCollection(List<double> collection, double item)
- {
- lock (m_lock)
- {
- collection.Add(item);
- }
- }
- protected override void EnumerateCollection(List<double> collection)
- {
- lock (m_lock)
- {
- double sum = collection.Sum();
- }
- }
- protected override double CreateElement(int index)
- {
- return (double)index;
- }
- }
- sealed class ConcurrentBagTester : ConcurrentCollectionTester<double, ConcurrentBag<double>>
- {
- // A ConcurrentBag<T> is supposed to be thread-safe with no need for
- // any locking.
- protected override void AddToCollection(ConcurrentBag<double> collection, double item)
- {
- collection.Add(item);
- }
- protected override void EnumerateCollection(ConcurrentBag<double> collection)
- {
- double sum = collection.Sum();
- }
- protected override double CreateElement(int index)
- {
- return (double)index;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement