问题
I have a CPU intensive task and I want it to use less CPU and take up more time.
I'm loading a massive amount of SCNNodes to a scene at start-up. It takes up a lot of memory, and I'd like it to work on it at a safe rate instead of lagging up my system or potentially crashing it.
Here's the code I'm using to load the nodes.
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void){
NSLog(@"Start Loading Level");
SCNNode *cameraNode = [SCNNode node];
cameraNode.camera = [SCNCamera camera];
cameraNode.camera.zFar = 5000;
cameraNode.position = SCNVector3Make(0, 3000, 0);
cameraNode.rotation = SCNVector4Make(1, 0, 0, -M_PI_2);
[scene.rootNode addChildNode:cameraNode];
for (int i = 0; i < 100000; i++)
{
int side = 3000;
SCNNode *node = [SCNNode node];
node.geometry = [SCNBox boxWithWidth:1 height:1 length:1 chamferRadius:0];
node.position = SCNVector3Make(arc4random_uniform(side) - side / 2.0,
0,
arc4random_uniform(side) - side / 2.0);
[scene.rootNode addChildNode:node];
}
dispatch_async(dispatch_get_main_queue(), ^(void){
NSLog(@"Finished");
});
});
Here are the statistics:


回答1:
It might not be the best way to do this, but have you looked at prepareobject:
?
Creating the NSObjects themselves shouldn't be that much of a problem, but preparing the geometry and adding it to the scene probably is. Bu deffering this step to a secondary thread you'll save some CPU and make the scene not stop until the node is ready to be added.
Once each node is ready, (completion handler) just add it to the scene. I won't throttle the loading, but it will at least handle it in a safer way for the rest of your app.
https://developer.apple.com/library/prerelease/ios/documentation/SceneKit/Reference/SCNSceneRenderer_Protocol/index.html#//apple_ref/occ/intfm/SCNSceneRenderer/prepareObjects:withCompletionHandler:
-(void)prepareLevel{
// Mutable Array to save the nodes
NSMutableArray *nodes = [[NSMutableArray alloc] init];
for (int i = 0; i < 100000; i++)
{
int side = 3000;
SCNNode *node = [SCNNode node];
node.geometry = [SCNBox boxWithWidth:1 height:1
length:1 chamferRadius:0];
node.position = SCNVector3Make(arc4random_uniform(side) - side / 2.0,
0,
arc4random_uniform(side) - side / 2.0);
[nodes addObject:node];
}
[mySCNView prepareObjects:nodes withCompletionHandler:^(BOOL success) {
for(SCNNode*node in nodes){
[scene.rootNode addChildNode:node];
}
}];
}
回答2:
Two ideas:
Use NSOperationQueue, it has the method setThreadPriority: which can be used to throttle the load to some extend.
Because you are dispatching on an asynchronous queue, maybe you can insert a sleep() function after processing every 100th Element or so. This should reduce the amount of work for the processor because the thread stalls for some percentage of the time, but it won't make your UI laggy, because its just a background queue.
Obviously this is going to sacrifice CPU load for execution time.
回答3:
It looks like you're not doing anything to limit the number of simultaneous operations. Doing this is probably going to be more effective than trying to throttle CPU usage as CPU usage throttling is a vague concept by comparison.
To limit the number of concurrent operations, you can do one of the following:
Make a custom
dispatch_queue
usingdispatch_queue_create("com.myApp.loadQueue", DISPATCH_QUEUE_SERIAL)
.DISPATCH_QUEUE_SERIAL
prevents blocks in the queue from running concurrently.As @JoJoe mentioned in their answer, use an
NSOperationQueue
. I'd suggest usingsetConcurrentOperationCount:
rather thansetThreadPriority:
to limit the number of concurrent operations. If you don't want to bother with setting up your ownNSOperation
subclass you can useNSBlockOperation
.
来源:https://stackoverflow.com/questions/29705842/throttle-cpu-usage-on-background-thread