Helper class to run a set of tasks in parallel. This class uses a number of worker threads witch will execute the queued tasks in parallel as much as possible. The worker threads are background threads and you must call Dispose() or Finish() to ensure all the tasks are finished
Inheritance: IDisposable
コード例 #1
0
        public void ParallelRunnerFlushTasksTest()
        {
            for (int count = 0; count < 20; count++)
            {
                using (TaskExecutor runner = new TaskExecutor())
                {
                    int i = 0;
                    double r;

                    foreach (var num in Enumerable.Range(0, count))
                    {
                        runner.AddTask(() =>
                        {
                            for (int j = 0; j < 1000; j++)
                            {
                                r = Math.Sin(0.234234) * Math.Atan(j);
                            }
                            Interlocked.Increment(ref i);
                        });
                    }

                    (i <= count).Should().BeTrue();

                    runner.FlushTasks();

                    i.Should().Be(count);

                    runner.Finish();

                    i.Should().Be(count);
                }
            }
        }
コード例 #2
0
        public void QueuedTaskRunnerErrorTest()
        {
            Action action = () => { throw new InvalidOperationException("boom"); };
            int calledTimes = 0;
            int baseThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
            using (TaskExecutor runner = new TaskExecutor(1))
            {
                runner.HasErrors.Should().BeFalse();
                runner.OnTaskError += (sender, args) =>
                {
                    sender.Should().BeSameAs(runner);
                    args.TaskException.Should().BeOfType<InvalidOperationException>();
                    System.Threading.Thread.CurrentThread.ManagedThreadId.Should().Be(baseThreadId);
                    calledTimes++;
                    args.WasHandled = true;
                };
                runner.OnThreadTaskError += (sender, args) =>
                {
                    sender.Should().BeSameAs(runner);
                    args.TaskException.Should().BeOfType<InvalidOperationException>();
                    baseThreadId.Should().NotBe(System.Threading.Thread.CurrentThread.ManagedThreadId);

                    args.WasHandled = true;
                };

                foreach (var n in Enumerable.Range(0, 5))
                {
                    runner.AddTask(action);
                }
                runner.Finish();
                runner.HasErrors.Should().BeTrue();
            }
            calledTimes.Should().Be(5);
        }
コード例 #3
0
        public void ParallelRunnerTestTaskCount()
        {
            using (TaskExecutor runner = new TaskExecutor())
            {
                const int count = 10;

                foreach (var num in Enumerable.Range(0, count))
                {
                    runner.AddTask(() => Thread.Sleep(100));
                }

                runner.TotalAddedTasks.Should().Be(count);
                runner.RemainingTasks.Should().Be(count);
                runner.ErrorCount.Should().Be(0);
                runner.FinishedTasksCount.Should().Be(0);

                runner.FlushTasks();

                runner.TotalAddedTasks.Should().Be(count);
                runner.RemainingTasks.Should().Be(0);
                runner.FinishedTasksCount.Should().Be(count);
                runner.ErrorCount.Should().Be(0);

                runner.Finish();

                runner.TotalAddedTasks.Should().Be(count);
                runner.RemainingTasks.Should().Be(0);
                runner.FinishedTasksCount.Should().Be(count);
                runner.ErrorCount.Should().Be(0);
            }
        }
コード例 #4
0
        public void QueuedTaskRunnerRunTaskTest()
        {
            const int nrTask = 100;
            int count = 0;

            using (TaskExecutor runner = new TaskExecutor(1))
            {
                for (int i = 0; i < nrTask; ++i)
                {
                    runner.AddTask(() => count++);
                }
            }

            count.Should().Be(nrTask);
        }
コード例 #5
0
 public void QueuedTaskRunnerWorkerThreadTest()
 {
     TaskExecutor runner = new TaskExecutor(1);
     bool hasThrown = false;
     try
     {
         runner.Finish();
         runner.Finish();
         runner.Dispose();
     }
     catch
     {
         hasThrown = true;
     }
     hasThrown.Should().BeFalse();
 }
コード例 #6
0
        public void ParallelRunnerTest()
        {
            const int task = 100;
            int sum = 0;

            using (TaskExecutor runner = new TaskExecutor())
            {
                object pad = new object();
                foreach (var num in Enumerable.Range(0, task))
                {
                    runner.AddTask(() =>
                    {
                        lock (pad) { sum++; }
                    });
                }
                runner.Finish();
            }
            sum.Should().Be(task);
        }
コード例 #7
0
        public void ParallelRunnerTestMultipleThreads()
        {
            using (TaskExecutor runner = new TaskExecutor(5))
            {

                int times = 1000;
                int taskCount = 10000;
                int currentTask = 0;
                int val = 0;

                Action task = null;
                task = () =>
                {
                    Interlocked.Increment(ref currentTask);
                    Interlocked.Increment(ref val);
                    if (currentTask <= taskCount)
                        runner.AddTask(task);
                    Thread.SpinWait((taskCount % 30) * 10000);
                };


                Enumerable.Range(0, times).ToList().ForEach(n => runner.AddTask(task));

                runner.FlushTasks();

                val.Should().Be(taskCount + times);
            }
        }
コード例 #8
0
        public void ParallelRunnerStressTest()
        {
            // 1000 increments with 2ms sleep each on 2 threads
            // 1000 * 2ms / 2threads = 1000ms min wait

            using (TaskExecutor runner = new TaskExecutor(2))
            {

                int val = 0;

                Enumerable.Range(0, 1000).ToList().ForEach(n => runner.AddTask(() => { Thread.Sleep(2); Interlocked.Increment(ref val); }));

                runner.FlushTasks();

                val.Should().Be(1000);
                runner.Finish();
            }
        }
コード例 #9
0
        public void ParallelRunnerHandeledExceptionTest()
        {
            using (TaskExecutor runner = new TaskExecutor())
            {
                runner.OnTaskError += (s, e) => e.WasHandled = true;

                InvalidOperationException x = new InvalidOperationException();

                runner.AddTask(() => { throw x; });

                Action action = () => runner.Finish();

                action.ShouldNotThrow();
            }
        }
コード例 #10
0
        public void ParallelRunnerExceptionTest()
        {
            using (TaskExecutor runner = new TaskExecutor())
            {
                InvalidOperationException x = new InvalidOperationException();

                runner.AddTask(() => { throw x; });

                AggregateException pex = null;

                try
                {
                    runner.Finish();
                }
                catch (AggregateException ex)
                {
                    pex = ex;
                }

                pex.InnerExceptions.Single().Should().Be(x);
            }
        }
コード例 #11
0
        public void ParallelRunnerFlushTestThreadSleep()
        {
            using (TaskExecutor runner = new TaskExecutor())
            {
                int i = 0;

                foreach (var n in Enumerable.Range(0, 10))
                {
                    runner.AddTask(() =>
                    {
                        if (n % 2 == 0)
                        {
                            Thread.Sleep(100);
                        }
                        Interlocked.Increment(ref i);
                    });
                }

                (i <= 10).Should().BeTrue();

                runner.FlushTasks();

                i.Should().Be(10);

                runner.Finish();

                i.Should().Be(10);
            }
        }
コード例 #12
0
        public void ParallelRunnerFlushTestAutoThreads()
        {
            using (TaskExecutor runner = new TaskExecutor())
            {
                int i = 0;

                const int count = 10;

                foreach (var n in Enumerable.Range(0, count))
                {
                    runner.AddTask(() =>
                    {
                        if (n % 2 == 0)
                        {
                            Thread.SpinWait(int.MaxValue / 200);
                        }
                        Interlocked.Increment(ref i);
                    });
                }

                (i <= count).Should().BeTrue();

                runner.FlushTasks();

                i.Should().Be(count);

                runner.Finish();

                i.Should().Be(count);
            }
        }