Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multi-threading in SpriteKit

I have divided this question into 2 parts. One more specific question about multithreading concerning a specific project. And one question about how multithreading ties into SpriteKit in general.

First question: I'm currently working on a test project to learn more about optimization in SpriteKit. In my test project I have over 2000 spriteNodes, each with some basic AI moving the node with actions.

I can see a significant increase in performance if set the Alpha = 0 to the nodes that are not currently within the screen area. But of course, performing this check in the update function on over 2000 nodes increases the load instead. Could it be possible to use multithreading in any way to take some load of the main thread. For example to make this check on an other thread.

General question: I couldn't find very much information about multithreading in SpriteKit so id like to get a better understanding about the whole topic, here are some guideline questions that I personally have. But if you want, and have the knowledge, feel free to expand outside this scope with any information you think is important.

  • When would it make sens to use multi-threading in SpriteKit?
  • What are the main limitations and pitfalls using multi-threading
  • How would I create a basic multi-thread example. Can I use swift to create the code? where do I put the code? were do I get started?
  • What things should i keep in mind regarding multi-threading and the rendering cycle.
  • Is there any difference between the threads. Are they "designed" to be used for different things?
  • Do you know any good article or learning resource to learn more about multi-threading?
like image 319
Magnus Ewerlöf Avatar asked Jul 14 '17 15:07

Magnus Ewerlöf


1 Answers

Okay so I have been doing some research and now I have a basic understanding about multi-threading in SpriteKit. I decided to sum it all up here so other people who know little or nothing about the concept can get started.

Basic overview. CPU cores and multi-threading

Multi-threading is a way to make the CPU work on more then one process at the same time. Each process would have its own Thread. Now this allows us to multitask. like surfing the web and watching a movie at the same time. If these processes would run on the same thread. The movie would freeze when reloading the webpage until the reload is complete.

Threads and CPU cores are 2 different things. The CPU core is the hardware the makes the calculations, while the Thread is more like a pipeline feeding the CPU with things to calculate. So from the example above there would be 2 pipes. One from the web browser, and one from the movie player feeding the CPU with information to calculate. The CPU would then alternate between these two pipes performing calculations for both, giving them somewhat equal attention. This doesn't mean that using two threads would improve the performance of the CPU. but it allows the two applications to share the resources of the CPU.

Multi-threading and SpriteKit

If multi-threading only allows us to share the CPU and run multiple calculations at the same time. how would it improve the performance in SpriteKit?

Well. If your device only have 1 CPU core. All we can really do is to separate tasks into different priorities to ensure that our main thread gets the most attention. And we want to give the main thread the most attention (from the cpu) to keep the FPS high, because this is the thread our render cycle uses. So if we have some calculations that doesn't need to be completed right away we could run them on an other thread with lower priority.

BUT! if your device have 2 CPU cores, like most IOS devices have. You could really improve the performance of your game. As said before, our render cycle runs on our main thread. you want this thread to have enough resources to complete all its calculations before its time to render the next frame. (or you will loose frame rate). The main thread connects to only ONE core. So when you are peaking at 100% CPU usage with almost 0 FPS. you are actually only using half of the CPU resources available on the device.

But with multi-threading you could take some load of the main thread and put it on the second core instead. In a test project I managed to get 150% cpu usage with 60 fps! Its weird to have 150% cpu usage but its actually showing the combined usage of the 2 cores. if you have 3 cores the maximum would be 300%.

I know this sounds too good to be true, and it actually kind of is, as you will find out in the next section.

Limitations and drawbacks with Multi-threading

Its great to be able to utilise the resources available from the second core. But, there are some calculations that has to run on the main thread. If we take a look at the render cycle. All the light blue areas has to run on the main thread. evaluate actions, simulate physics, constraints and render. And these are often the most heavy calculations in a project, and pretty quickly it become the bottleneck for performance. Still, depending on the structure of your project, a lot of other calculations like measuring distances, updating positions, AI decisions etc, could be put on the second core to take some load of the main thread. enter image description here

How do i implement multithreading in my project.

The easiest way to do multi-threading in SpriteKit is to use something called: Grand Central Dispatch (GCD). This API comes out of the box, no need for including anything in your project. GCD is doing all the heavy lifting for managing your threads in a safe and efficient way.

Gettings started with GDC is very simple. The code below would run myFunction on an other thread.

run(SKAction.run(myFunction, queue: DispatchQueue.global(qos: .background)))

func myFunction(){
// Do some work here
}

You could also define a dispatchQueue directly inside a function. or anywhere in your code. All your work inside the dispatch block will be executed asynchronously on an appropriate thread selected by GDC.

func myFunction(){

    DispatchQueue.global(qos: .background).async {
       //Do some work here...
    }

}

**** TO BE CONTINUED ***

like image 104
Magnus Ewerlöf Avatar answered Sep 30 '22 13:09

Magnus Ewerlöf