void PrepareParallelTasks() { //create a collection of task that will run in parallel on several threads. //the number of threads and tasks to perform are not dependent. _multiParallelTasks = new MultiThreadedParallelTaskCollection(NUM_OF_SVELTO_THREADS, true); //in this case though we just want to perform a task for each thread //ParticlesCPUKernel is a task (IEnumerator) that executes the //algebra operation on the particles. Each task perform the operation //on particlesPerThread particles #if BENCHMARK pc = new ParticleCounter(particlesPerThread - 16); #else _pc = new ParticleCounter(0); #endif #if OLD_STYLE //calculate the number of particles per thread uint particlesPerThread = _particleCount / NUM_OF_SVELTO_THREADS; for (int i = 0; i < NUM_OF_SVELTO_THREADS; i++) { _multiParallelTasks.Add(new ParticlesCPUKernel((int)(particlesPerThread * i), (int)particlesPerThread, this, _pc)); } #else var particlesCpuKernel = new ParticlesCPUKernel(this); _multiParallelTasks.Add(ref particlesCpuKernel, (int)_particleCount); #endif }
public IEnumerator TestMultiThreadParallelTaskReset() { var test = new MultiThreadedParallelTaskCollection("test", 4, false); Token token = new Token(); int done = 0; test.onComplete += () => done++; test.Add(new WaitEnumerator(token)); test.Add(new WaitEnumerator(token)); test.Add(new WaitEnumerator(token)); test.Add(new WaitEnumerator(token)); test.Run(); yield return(new WaitForSeconds(0.5f)); token.count = 3; test.Stop(); test.Complete(); test.Dispose(); Assert.That(done == 1); Assert.AreEqual(4, token.count); }
public IEnumerator ParallelMultiThread() { yield return(null); var parallelMultiThread = new MultiThreadedParallelTaskCollection("test", 2, true); parallelMultiThread.Add(new SlowTask()); parallelMultiThread.Add(new SlowTask()); var sw = System.Diagnostics.Stopwatch.StartNew(); parallelMultiThread.Complete(); parallelMultiThread.Dispose(); sw.Stop(); Assert.That(sw.ElapsedMilliseconds, Is.AtLeast(900)); Assert.That(sw.ElapsedMilliseconds, Is.AtMost(1100)); }
public IEnumerator TestMultiThreadParallelTaskCompletes() { yield return(null); var test = new MultiThreadedParallelTaskCollection("test", 4, false); bool done = false; test.onComplete += () => done = true; Token token = new Token(); test.Add(new WaitEnumerator(token)); test.Add(new WaitEnumerator(token)); test.Add(new WaitEnumerator(token)); test.Add(new WaitEnumerator(token)); var multiThreadRunner = new MultiThreadRunner("test", true); test.RunOnScheduler(multiThreadRunner); DateTime now = DateTime.Now; yield return(null); while (test.isRunning) { yield return(null); } var totalSeconds = (DateTime.Now - now).TotalSeconds; Assert.Greater(totalSeconds, 1.9); Assert.Less(totalSeconds, 2.1); Assert.That(done, Is.True); Assert.AreEqual(4, token.count); test.Dispose(); multiThreadRunner.Dispose(); }
public IEnumerator TestStopMultiThreadParallelTask() { var test = new MultiThreadedParallelTaskCollection("test", 4, false); Token token = new Token(); bool done = false; test.onComplete += () => done = true; test.Add(new WaitEnumerator(token)); test.Add(new WaitEnumerator(token)); test.Add(new WaitEnumerator(token)); test.Add(new WaitEnumerator(token)); test.Run(); yield return(new WaitForSeconds(0.5f)); test.Stop(); test.Dispose(); Assert.That(done, Is.False); Assert.AreEqual(token.count, 0); }
IEnumerator WaitForEntityViewsAdded() { //Engines are usually designed to be able to cope with dynamic adding and removing of entities, //but in this case I needed to know when the entities are ready to be processed. This wouldn't be //strictly necessary if I coded the engine in a different way, but I decided to keep it simpler and more readable. //That's why the engine starts immediately a task that waits for the EntityViews to be added(it assumes that all the //entities are created on the same frame).This demo aims to be allocation free during the main execution, that's //why all the tasks are prepared before hand. In this step, we prepare just one task that runs the main operations //that must be executed on the entities. int count = 0; #if FIRST_TIER_EXAMPLE || SECOND_TIER_EXAMPLE ReadOnlyCollectionStruct <BoidEntityView> _entityViews; #endif #if FOURTH_TIER_EXAMPLE || THIRD_TIER_EXAMPLE BoidEntityView[] _entityViews; #endif do { #if FIRST_TIER_EXAMPLE || SECOND_TIER_EXAMPLE _entityViews = entitiesDB.QueryEntityViews <BoidEntityView>(); count = _entityViews.Count; #endif #if FOURTH_TIER_EXAMPLE || THIRD_TIER_EXAMPLE _entityViews = entitiesDB.QueryEntities <BoidEntityView>(ExclusiveGroups.BoidGroup, out count); #endif yield return(null); } while (count == 0); #if TURBO_EXAMPLE int numberOfThreads = (int)Mathf.Min(NUM_OF_THREADS, count); var countn = count / numberOfThreads; _multiParallelTask = new MultiThreadedParallelTaskCollection((uint)numberOfThreads); for (int i = 0; i < numberOfThreads; i++) { _multiParallelTask.Add(new BoidEnumerator(_entityViews, countn * i, countn)); } #elif FIRST_TIER_EXAMPLE || SECOND_TIER_EXAMPLE || THIRD_TIER_EXAMPLE || FOURTH_TIER_EXAMPLE _boidEnumerator = new BoidEnumerator(_entityViews, 0, count); #endif _testEnumerator = new TestEnumerator(_printEntityView); Update().RunOnScheduler(StandardSchedulers.updateScheduler); }
public BoidsSimulationEngine(ThreadSynchronizationSignal synchronizationSignal, Param param, int boidCount) { this.param = param; //Svelto.Tasks is based on the concept of tasks and runners to run them. Runners can be many. I may even //write a Unity Jobs runner one day. The MultiThreadRunner is the Svelto.Tasks runner to run tasks //on other threads. For more information please check my Svelto.Tasks articles. //this runner will run the main loop _runner = new MultiThreadRunner("BoidSimulationSystem", 1); //MultiThreadedParallelTaskCollection enables massive parallelism on the CPU. I will create a Svelto.Tasks //job for each boid. These jobs will be then spread on 16 threads on an I7. _parallelJobs = new MultiThreadedParallelTaskCollection("BoidsSimulationJobs", (uint)(System.Environment.ProcessorCount * 2), true); //Svelto Tasks Jobs must be struct, as they must be instantiated multiple times, the first one //will be used as blueprint fro the other ones var jobInstance = new BoidSimulationJob(this, boidCount); //Create boidCount jobs and add them _parallelJobs.Add(ref jobInstance, boidCount); //the Synchronization signal is used to send signals between threads and allow synchronizations _synchronizationSignal = synchronizationSignal; _boidCount = boidCount; }