5

Imagine in your

 class NattyScene: SKScene {

you have perhaps a custom Field for the nodes, or something else that happens every frame. Now imagine you have some calculation, a nice example might be center of gravity ...

var globalCOG: CGPoint
func updateCOG() {
   .. say, get all the .position of all Spaceship ..
   globalCOG = .. some point
}

It would make great sense to put that on another thread, assuming issues like

  • it's threadsafe / fast to read the .positions
  • this other putative thread on another core, knows about SpriteKit frames (so that you can calculate until giveup time in the usual manner, etc, perhaps you may prefer to skip frame or whatever - the usual panoply of threaded game programming)
  • you can threadsafe/blahblah write the COG global back to the rest of SpriteKit

What's the deal on this?

  • What really is the modern idiom for this in Swift4 / SpriteKit
  • How do you force it to go on another whole physical core?

Any ideas?


override func update(_ currentTime: TimeInterval) {

    let x = safely get info from a thread on another physical core on the device
    print("now that's cool")
}

on the other core ...

 func loopy() {

    let x = safely look at info on NattyScene
    let globalCOG = calculation
}

Note, KOD has pointed to DispatchQueue, which is great - but is there any way to ensure it's really on another core?

Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
Fattie
  • 27,874
  • 70
  • 431
  • 719
  • use `DispatchQueue` when you need to process something outside of the main thread, but if it has to do with rendering, you want to make sure that gets done on the main thread (which you can get back to with `DispatchQueue.main` – Knight0fDragon Nov 09 '17 at 13:58
  • Now what you are asking for in this example would be dangerous on a multi thread, because your spaceship positions could change in your main thread, so you would need to somehow ensure that changes did not happen by locking the main thread (Do not do this) or simply copy the ships and ignore any future changes to position – Knight0fDragon Nov 09 '17 at 14:01
  • https://www.raywenderlich.com/148513/grand-central-dispatch-tutorial-swift-3-part-1 – Knight0fDragon Nov 09 '17 at 14:09
  • hi @Knight0fDragon ! *"would be dangerous..."* of course, all threaded game programming is dangerous; that's the norm. (in the "cog" example, it would be "approximate_cog", as it may be out of sync, unset, impossible to read just now - all the usual woes.) – Fattie Nov 09 '17 at 17:25
  • no.... there are safe ways to do multi threading, and there are dangerous ways lol. Not all multi-threading is dangerous, You just need to make sure that what happens on 1 thread is not being manipulated on another. Your example does not do this lol. – Knight0fDragon Nov 09 '17 at 17:29
  • right - that's what I'm saying. my example is safe. the "COG" thread merely looks at the tanks, and their positions. (it does not matter how many tanks there are, if they come or go or whatever). notice as it says "**safely** look at the tanks on NattyScene". the main thread only looks at the float "COG", whatever COGthread has at the moment. the COG thread doesn't move the tanks. the tank thread only reads the float. in short - they are "read only threads"..... – Fattie Nov 09 '17 at 17:41
  • it is not "safe", because your COG may be inaccurate. The threads may pass fine, but the results may end up wrong because the point you are calculating is not the point where the tank is at, you might be writing to the position as your other thread is reading it. And no, there is no easy way to handle multi core. You really should let the system decide that for you because there are things going on that is outside of your control, like background apps running and system services, so it is going to be a pain to ensure parallelism between cores. if you must, you can always take the C route – Knight0fDragon Nov 09 '17 at 17:49
  • 1
    nah dude, it is an **approximate** COG, as mentioned. (it's a basic of game programming.) if you need the "absolute, platonic" COG you can't calculate it on another thread! (of course you have to lock up a value to read/write it, across threads/devices.) – Fattie Nov 09 '17 at 18:10
  • "And no, there is no easy way to handle multi core" that sucks. you think it has to be done at the c level eh. :/ – Fattie Nov 09 '17 at 18:10
  • 1
    You can use queue relationships to let GCD know more information about the work you're doing. Watch [this WWDC session](https://developer.apple.com/videos/play/wwdc2017/706/), it's very good. – allenh Dec 04 '17 at 14:54

1 Answers1

4

Nice question, unfortunately I don't think this is possible for 2 main reasons.

Reason 1

You don't have this kind of low level access in iOS.

The OS is the one who decides which thread runs on which core. It also has the capability of turning on and off the cores depending on several conditions beyond the scope of your app.

E.g. When in Grand Central Dispatch you write

DispatchQueue.global(qos: .background).async { }

You have no guarantee the closure will be executed on a different core.

Reason 2

The Game Run Loop of SpriteKit does execute a bunch of stuff

  1. call update
  2. evaluates actions
  3. simulates physics
  4. applies constraints

Your idea does imply the execution of the following steps within the call update phase

  1. move on a "background" thread
  2. perform some heavy computations
  3. bring the result back to the main thread

But at this point you have no guarantee the Game Run Loop is still in the call update phase. It could be in the evaluates actions or it could even be working at the next frame. On the other hand you have no more than 16 milliseconds to render each frame.

Possible Solution

Instead of targeting another CPU core you could take full advantage of the 64 bits allowed by the current core. Look at this Q/A about SceneKit where are listed the benefits of SIMD.

Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
  • 3
    Fantastic info Luca. One point: *"at this point you have no guarantee the Game Run Loop is still in the call update phase"* to be absolutely clear, I am only talking about processing calculations, where it is completely unnecessary to have an answer each frame. (A trivial example in game development - you may have some sort of ongoing AI system which calculates some concept. It may only have a new result every say second or two! It's awesome to get that info whenever you get it (say every second or so) - I am not talking here of inside-the-frame calculations.) – Fattie Nov 12 '17 at 19:31
  • the SIMD tip is amazing, thanks. You shouldn't tell anyone :) – Fattie Nov 12 '17 at 19:32
  • I think you're going to win the bounty, Luca! :) – Fattie Dec 01 '17 at 16:06
  • @Fattie Let's see :) – Luca Angeletti Dec 04 '17 at 13:52