public void Reuse() { var onThread = new int[4]; var sums = new int[4]; var _ = new GameState(); using (var runner = new JobRunner(_, 4, 10)) { runner.Initialize(); // setup the jobs Job <int> j1, j2, j3, j4; { j1 = runner.CreateJob(TestTask, 0); j2 = runner.CreateJob(TestTask, 1); j3 = runner.CreateJob(TestTask, 2); j4 = runner.CreateJob(TestTask, 3); } // wait for them to finish var comp = runner.StartJobs(j1, j2, j3, j4); comp.WaitForCompletion(); // got the right answer Assert.Equal(49_995_000, sums[0]); Assert.Equal(49_995_000, sums[1]); Assert.Equal(49_995_000, sums[2]); Assert.Equal(49_995_000, sums[3]); // run them _again_ var comp2 = runner.StartJobs(j1, j2, j3, j4); comp2.WaitForCompletion(); // got the right answer, again Assert.Equal(2 * 49_995_000, sums[0]); Assert.Equal(2 * 49_995_000, sums[1]); Assert.Equal(2 * 49_995_000, sums[2]); Assert.Equal(2 * 49_995_000, sums[3]); } // just a dumb task to do void TestTask(GameState ignore, int ix) { for (var i = 0; i < 10_000; i++) { sums[ix] += i; } } }
public void Aggressive() { var observedToRun = 0; var rand = new Random(2018_11_27); var _ = new GameState(); // more threads than tasks using (var runner = new JobRunner(_, 16, 100)) { runner.Initialize(); Stress(runner); } // fewer threads than tasks using (var runner = new JobRunner(_, 4, 100)) { runner.Initialize(); Stress(runner); } void Stress(JobRunner runner) { var jobs = Enumerable.Range(0, 100).Select(r => runner.CreateJob(TestTask, r)).ToArray(); observedToRun = 0; var expectedToRun = 0; for (var i = 0; i < 10_000; i++) { var numJobs = rand.Next(8) + 1; var subset = jobs.OrderBy(o => Guid.NewGuid()).Take(numJobs).ToArray(); JobsCompletionToken tok; switch (numJobs) { case 1: tok = runner.StartJobs(subset[0]); break; case 2: tok = runner.StartJobs(subset[0], subset[1]); break; case 3: tok = runner.StartJobs(subset[0], subset[1], subset[2]); break; case 4: tok = runner.StartJobs(subset[0], subset[1], subset[2], subset[3]); break; case 5: tok = runner.StartJobs(subset[0], subset[1], subset[2], subset[3], subset[4]); break; case 6: tok = runner.StartJobs(subset[0], subset[1], subset[2], subset[3], subset[4], subset[5]); break; case 7: tok = runner.StartJobs(subset[0], subset[1], subset[2], subset[3], subset[4], subset[5], subset[6]); break; case 8: tok = runner.StartJobs(subset[0], subset[1], subset[2], subset[3], subset[4], subset[5], subset[6], subset[7]); break; default: throw new Exception("wuh?"); } expectedToRun += numJobs; tok.WaitForCompletion(); } Assert.Equal(expectedToRun, observedToRun); } // Just does a bunch of junk void TestTask(GameState ignore, int ix) { var sum = 0; for (var i = 0; i < 10_000; i++) { sum += i; } Interlocked.Increment(ref observedToRun); } }
public void InParallel() { var startTicks = new long[4]; var stopTicks = new long[4]; var onThread = new int[4]; var sums = new int[4]; var _ = new GameState(); using (var runner = new JobRunner(_, 4, 10)) { runner.Initialize(); // setup the jobs Job <int> j1, j2, j3, j4; { j1 = runner.CreateJob(TestTask, 0); j2 = runner.CreateJob(TestTask, 1); j3 = runner.CreateJob(TestTask, 2); j4 = runner.CreateJob(TestTask, 3); } // wait for them to finish var comp = runner.StartJobs(j1, j2, j3, j4); comp.WaitForCompletion(); // no goofy time travel for (var i = 0; i < 4; i++) { Assert.True(stopTicks[i] > startTicks[i]); } // ran on different thread Assert.False(onThread[0] == onThread[1]); Assert.False(onThread[0] == onThread[2]); Assert.False(onThread[0] == onThread[3]); Assert.False(onThread[1] == onThread[2]); Assert.False(onThread[1] == onThread[3]); Assert.False(onThread[2] == onThread[3]); // got the right answer Assert.Equal(49_995_000, sums[0]); Assert.Equal(49_995_000, sums[1]); Assert.Equal(49_995_000, sums[2]); Assert.Equal(49_995_000, sums[3]); } // just a dumb task to do void TestTask(GameState ignore, int ix) { startTicks[ix] = Stopwatch.GetTimestamp(); onThread[ix] = Thread.CurrentThread.ManagedThreadId; Thread.Sleep(10); for (var i = 0; i < 10_000; i++) { sums[ix] += i; } stopTicks[ix] = Stopwatch.GetTimestamp(); } }