【发布时间】:2017-05-02 00:50:23
【问题描述】:
我正在创建大量 SCNNode 并将其添加到 SceneKit 场景中,这会导致应用冻结一两秒。
我想我可以通过使用DispatchQueue.global(qos: .background).async() 将所有操作放在后台线程中来解决这个问题,但没有骰子。它的行为完全相同。
我看到this answer 并在添加它们之前将节点通过SCNView.prepare(),希望它会减慢后台线程并防止阻塞。没有。
这是一个重现问题的测试函数:
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 可以接受的任何速度添加新节点。相反,应用程序完全冻结了一两秒钟,然后所有新节点立即出现。
为什么会出现这种情况,如何在不阻塞主线程的情况下添加大量节点?
【问题讨论】:
-
如何将每个 SCNNode 添加作为自己的任务添加到队列中?然后让系统决定何时执行每个任务。现在,您创建一个添加 5000 个节点的大任务,而不是创建每个添加一个节点的 5000 个任务。在这种情况下不可能有并发。
-
他要求的并发是减少/消除主(UI)线程上的冻结。在一个后台线程上完成所有节点创建很好。冻结发生在
prepare()和addChildNode()调用中。 -
您是否尝试将所有新节点添加到后台线程中的单个父节点,然后通过一次调用 addChildNode() 将该节点添加到根节点?
-
@ScottAhten 我尝试了你的建议,但不幸的是它没有消除或减少阻塞。
-
@KarlSigiscar 我尝试了你的建议。当任务被异步添加到队列中时,它在崩溃之前产生了 74 个线程。同步添加时,阻塞并没有减少。
标签: ios swift multithreading swift3 scenekit