如何在不阻塞主线程的情况下添加SCNNodes?
我正在创建大量SCNNode并将其添加到SceneKit场景,这会导致应用冻结一到两秒钟.
I'm creating and adding a large number of SCNNodes to a SceneKit scene, which causes the app to freeze for a second or two.
我想我可以通过使用DispatchQueue.global(qos: .background).async()
将所有动作放在后台线程中来解决此问题,但不要掷骰子.它的行为完全相同.
I thought I could fix this by putting all the action in a background thread using DispatchQueue.global(qos: .background).async()
, but no dice. It behaves exactly the same.
我看到了此答案,并通过
I saw this answer and put the nodes through SCNView.prepare()
before adding them, hoping it would slow down the background thread and prevent blocking. It didn't.
这是一个重现问题的测试功能:
Here's a test function that reproduces the problem:
func spawnNodesInBackground() {
// put all the action in a background thread
DispatchQueue.global(qos: .background).async {
var nodes = [SCNNode]()
for i in 0...5000 {
// create a simple SCNNode
let node = SCNNode()
node.position = SCNVector3(i, i, i)
let geometry = SCNSphere(radius: 1)
geometry.firstMaterial?.diffuse.contents = UIColor.white.cgColor
node.geometry = geometry
nodes.append(node)
}
// run the nodes through prepare()
self.mySCNView.prepare(nodes, completionHandler: { (Bool) in
// nodes are prepared, add them to scene
for node in nodes {
self.myRootNode.addChildNode(node)
}
})
}
}
当我调用spawnNodesInBackground()
时,我希望场景能够继续正常渲染(也许以降低的帧速率),而新节点的添加速度则应以CPU可以接受的任何速度进行.相反,该应用程序完全冻结了一两秒钟,然后所有新节点立即出现.
When I call spawnNodesInBackground()
I expect the scene to continue rendering normally (perhaps at a reduced frame rate) while new nodes are added at whatever pace the CPU is comfortable with. Instead the app freezes completely for a second or two, then all the new nodes appear at once.
为什么会这样,如何在不阻塞主线程的情况下添加大量节点?
Why is this happening, and how can I add a large number of nodes without blocking the main thread?
我认为使用DispatchQueue不能解决此问题.如果我替代其他任务而不是创建SCNNode
,那么它可以按预期工作,因此我认为问题与SceneKit有关.
I don't think this problem is solvable using the DispatchQueue. If I substitute some other task instead of creating SCNNode
s it works as expected, so I think the problem is related to SceneKit.
此问题的答案表明SceneKit具有它自己的私有后台线程,将所有更改批处理到该线程.因此,无论我使用什么线程创建SCNNodes
,它们都最终与渲染循环位于同一线程的同一队列中.
The answers to this question suggest that SceneKit has its own private background thread that it batches all changes to. So regardless of what thread I use to create my SCNNodes
, they all end up in the same queue in the same thread as the render loop.
我正在使用的丑陋解决方法是一次在SceneKit的委托renderer(_:updateAtTime:)
方法中一次添加几个节点,直到它们全部完成为止.
The ugly workaround I'm using is to add the nodes a few at a time in SceneKit's delegated renderer(_:updateAtTime:)
method until they're all done.