public void SingleThreadPerformanceTest() { const int count = 500000; var timeProvider = Time.DefaultTimeProvider; using (var group = new ThreadGroup(1, 1)) { var queue = group.GetQueueForType <VoidWorkItem>(); queue.DefaultStepCount = 1024; var item = new VoidWorkItem(); var beforeEnqueue = timeProvider.Ticks; for (int i = 0; i < count; i++) { queue.Enqueue(ref item); } var afterEnqueue = timeProvider.Ticks; var beforeWait = timeProvider.Ticks; queue.WaitUntilDrained(); var afterWait = timeProvider.Ticks; Console.WriteLine( "Enqueue took {0:0000.00}ms, Wait took {1:0000.00}ms. Final thread count: {2}", TimeSpan.FromTicks(afterEnqueue - beforeEnqueue).TotalMilliseconds, TimeSpan.FromTicks(afterWait - beforeWait).TotalMilliseconds, group.Count ); } }
public void WaitUntilDrained() { const int count = 50; using (var group = new ThreadGroup(1, createBackgroundThreads: true, name: "WaitUntilDrainedSplitsQueue") { DefaultConcurrencyPadding = 0 }) { var queue = group.GetQueueForType <BlockingWorkItem>(); var item = new BlockingWorkItem(); for (int i = 0; i < count; i++) { queue.Enqueue(ref item, notifyChanged: false); } group.NotifyQueuesChanged(); var barrier = new BlockingWorkItem { Signal = new AutoResetEvent(false) }; queue.Enqueue(ref barrier, notifyChanged: false); Assert.IsFalse(queue.WaitUntilDrained(5), "waitUntilDrained 1"); group.NotifyQueuesChanged(); Assert.IsFalse(queue.WaitUntilDrained(5), "waitUntilDrained 2"); barrier.Signal.Set(); Assert.IsTrue(queue.WaitUntilDrained(500), "waitUntilDrained 3"); Assert.IsTrue(queue.WaitUntilDrained(5), "waitUntilDrained 4"); } }
public void PaddingTest() { using (var group = new ThreadGroup(2, createBackgroundThreads: true, name: "PaddingTest") { DefaultConcurrencyPadding = 1 }) { var queue = group.GetQueueForType <HighPriorityBlockingWorkItem>(); var barrier1 = new HighPriorityBlockingWorkItem { Signal = new AutoResetEvent(false) }; queue.Enqueue(barrier1); var barrier2 = new HighPriorityBlockingWorkItem { Signal = new AutoResetEvent(false) }; queue.Enqueue(barrier2); group.NotifyQueuesChanged(); Thread.Sleep(300); Assert.AreEqual(1, queue.ItemsInFlight); barrier1.Signal.Set(); Assert.IsFalse(queue.WaitUntilDrained(150)); Assert.AreEqual(1, queue.ItemsInFlight); barrier2.Signal.Set(); Assert.IsTrue(queue.WaitUntilDrained(150)); } }
public void NotifyOverheadTest() { const int count = 800; var timeProvider = Time.DefaultTimeProvider; using (var group = new ThreadGroup(4, createBackgroundThreads: true, name: "NotifyOverheadTest") { DefaultConcurrencyPadding = 0 }) { var queue = group.GetQueueForType <SlightlySlowWorkItem>(); var item = new SlightlySlowWorkItem(); var beforeEnqueue = timeProvider.Ticks; for (int i = 0; i < count; i++) { queue.Enqueue(ref item, notifyChanged: true); } var afterEnqueue = timeProvider.Ticks; var beforeWait = timeProvider.Ticks; queue.WaitUntilDrained(10000); var afterWait = timeProvider.Ticks; var perItem = (afterWait - beforeWait) / (double)count / Time.MillisecondInTicks; Console.WriteLine( "Enqueue took {0:0000.00}ms, Wait took {1:0000.00}ms. Est speed {3:0.000000}ms/item Final thread count: {2}", TimeSpan.FromTicks(afterEnqueue - beforeEnqueue).TotalMilliseconds, TimeSpan.FromTicks(afterWait - beforeWait).TotalMilliseconds, group.Count, perItem ); } }
public void PriorityTest() { using (var group = new ThreadGroup(2, createBackgroundThreads: true, name: "PriorityTest") { DefaultConcurrencyPadding = 0 }) { var queue = group.GetQueueForType <HighPriorityBlockingWorkItem>(); var barrier1 = new HighPriorityBlockingWorkItem { Signal = new AutoResetEvent(false) }; queue.Enqueue(barrier1); var barrier2 = new HighPriorityBlockingWorkItem { Signal = new AutoResetEvent(false) }; queue.Enqueue(barrier2); var barrier3 = new HighPriorityBlockingWorkItem { Signal = new AutoResetEvent(false) }; queue.Enqueue(barrier3); group.NotifyQueuesChanged(); // HACK: Give the thread group time to start processing high priority items while (queue.ItemsInFlight < group.ThreadCount) { Thread.Sleep(1); } var voidQueue = group.GetQueueForType <VoidWorkItem>(); var testItem = new VoidWorkItem(); for (int i = 0; i < 10; i++) { voidQueue.Enqueue(testItem); } group.NotifyQueuesChanged(); var ok = voidQueue.WaitUntilDrained(50); Assert.IsFalse(ok, "wait for low priority queue to drain while threads are blocked on high priority"); barrier1.Signal.Set(); Assert.IsFalse(voidQueue.WaitUntilDrained(50), "ensure new high priority item is claimed by thread that finished previous one"); barrier2.Signal.Set(); barrier3.Signal.Set(); ok = voidQueue.WaitUntilDrained(500); Assert.IsTrue(ok, "once high priority items are done the low priority ones should run"); } }
public static Future <T> Invoke <T> (this ThreadGroup group, Func <T> func, bool forMainThread = false) { var workItem = new FuncWorkItem <T> { Func = func, Future = new Future <T>() }; var queue = group.GetQueueForType <FuncWorkItem <T> >(forMainThread); queue.Enqueue(ref workItem); return(workItem.Future); }
public static SignalFuture Invoke(this ThreadGroup group, Action action, bool forMainThread = false) { var workItem = new ActionWorkItem { Action = action, Future = new SignalFuture() }; var queue = group.GetQueueForType <ActionWorkItem>(forMainThread); queue.Enqueue(ref workItem); return(workItem.Future); }
public void ManuallyStep() { using (var group = new ThreadGroup(0, 0)) { var queue = group.GetQueueForType <TestWorkItem>(); var item = new TestWorkItem(); Assert.IsFalse(item.Ran); queue.Enqueue(item); bool exhausted; queue.Step(out exhausted, 1); Assert.IsTrue(exhausted); Assert.IsTrue(item.Ran); } }
public void AutoSpawnMoreThreads() { using (var group = new ThreadGroup(0, 2)) { var queue = group.GetQueueForType <SleepyWorkItem>(); queue.Enqueue(new SleepyWorkItem()); group.NotifyQueuesChanged(); Assert.GreaterOrEqual(1, group.Count); queue.Enqueue(new SleepyWorkItem()); group.NotifyQueuesChanged(); Assert.GreaterOrEqual(2, group.Count); queue.WaitUntilDrained(); } }
public void MultipleThreadPerformanceTest() { const int count = 800; var timeProvider = Time.DefaultTimeProvider; using (var group = new ThreadGroup(4, createBackgroundThreads: true, name: "MultipleThreadPerformanceTest") { DefaultConcurrencyPadding = 0 }) { var queue = group.GetQueueForType <SlightlySlowWorkItem>(); var item = new SlightlySlowWorkItem(); var beforeEnqueue = timeProvider.Ticks; for (int i = 0; i < count; i++) { queue.Enqueue(ref item, notifyChanged: false); // Notify the group periodically that we've added new work items. // This ensures it spins up a reasonable number of threads. if ((i % 500) == 0) { group.NotifyQueuesChanged(); } } var afterEnqueue = timeProvider.Ticks; var beforeWait = timeProvider.Ticks; queue.WaitUntilDrained(10000); var afterWait = timeProvider.Ticks; var perItem = (afterWait - beforeWait) / (double)count / Time.MillisecondInTicks; Console.WriteLine( "Enqueue took {0:0000.00}ms, Wait took {1:0000.00}ms. Est speed {3:0.000000}ms/item Final thread count: {2}", TimeSpan.FromTicks(afterEnqueue - beforeEnqueue).TotalMilliseconds, TimeSpan.FromTicks(afterWait - beforeWait).TotalMilliseconds, group.Count, perItem ); } }
public void ManuallyStep() { using (var group = new ThreadGroup(0, createBackgroundThreads: true, name: "ManuallyStep") { DefaultConcurrencyPadding = 0 }) { var queue = group.GetQueueForType <TestWorkItem>(); var item = new TestWorkItem(); Assert.IsFalse(item.Ran); queue.Enqueue(item); bool exhausted; queue.Step(out exhausted, 1); Assert.IsTrue(exhausted); Assert.IsTrue(item.Ran); } }
public void AutoSpawnThread() { using (var group = new ThreadGroup(0, 1)) { var queue = group.GetQueueForType <TestWorkItem>(); var item = new TestWorkItem(); Assert.IsFalse(item.Ran); queue.Enqueue(item); Assert.AreEqual(0, group.Count); Assert.IsFalse(item.Ran); group.NotifyQueuesChanged(); Assert.AreEqual(1, group.Count); queue.WaitUntilDrained(); Assert.IsTrue(item.Ran); } }
public void MultipleThreadPerformanceTest() { const int count = 500000; var timeProvider = Time.DefaultTimeProvider; using (var group = new ThreadGroup(1)) { var queue = group.GetQueueForType <VoidWorkItem>(); queue.DefaultStepCount = 1024; var item = new VoidWorkItem(); var beforeEnqueue = timeProvider.Ticks; for (int i = 0; i < count; i++) { queue.Enqueue(ref item); // Notify the group periodically that we've added new work items. // This ensures it spins up a reasonable number of threads. if ((i % 20000) == 0) { group.NotifyQueuesChanged(); } } var afterEnqueue = timeProvider.Ticks; var beforeWait = timeProvider.Ticks; queue.WaitUntilDrained(); var afterWait = timeProvider.Ticks; Console.WriteLine( "Enqueue took {0:0000.00}ms, Wait took {1:0000.00}ms. Final thread count: {2}", TimeSpan.FromTicks(afterEnqueue - beforeEnqueue).TotalMilliseconds, TimeSpan.FromTicks(afterWait - beforeWait).TotalMilliseconds, group.Count ); } }