2015-04-17 4 views
12

Ho un compito intensivo della CPU e voglio che utilizzi meno CPU e occupi più tempo.Utilizzo della CPU del throttle sul thread di sfondo

Sto caricando una quantità enorme di nodi SCN in una scena all'avvio. Richiede molta memoria e mi piacerebbe lavorarci su con sicurezza, invece di rallentare il mio sistema o potenzialmente bloccarlo.

Ecco il codice che sto usando per caricare i nodi.

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"); 
    }); 
}); 

Qui ci sono le statistiche:

Image Usage over Time Image Memory

+1

Sarei più preoccupato dal fatto che SceneKit dovrà rendere tanti nodi. 100000 nodi sono incredibilmente grandi. – mnuages

+0

Questo è un caso di test. Potrei usare il codice del mio progetto, ma questo sembra avere il significato. –

+0

Suggerirei di usare dispatch_apply() con stride invece che per (;;) all'interno di dispatch_async() per creare contemporaneamente nodi. –

risposta

8

Potrebbe non essere il modo migliore per farlo, ma hai guardato prepareobject:?

Creare gli stessi file NSO non dovrebbe essere un problema, ma probabilmente è la preparazione della geometria e l'aggiunta alla scena. Se si effettua il deffering di questo passaggio su un thread secondario, si risparmia qualche CPU e la scena non si ferma finché il nodo non è pronto per essere aggiunto.

Una volta che ciascun nodo è pronto, (gestore di completamento) è sufficiente aggiungerlo alla scena. Non accellerò il caricamento, ma lo gestirò almeno in un modo più sicuro per il resto della tua 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]; 
     } 
    }]; 

} 
+0

Questo ha risolto il mio problema, grazie. Potresti modificare la risposta con un pezzo di codice di esempio? –

+0

Certo, lo farò quando torno a casa. – Moustach

+0

Ho aggiunto un esempio di codice semplice. C'è ancora spazio per l'ottimizzazione ma mostra l'uso di base di 'prepareObject:' – Moustach

2

due idee:

  1. Usa NSOperationQueue, esso ha il metodo SetThreadPriority: che può essere usato per strozzare il carico in certa misura.

  2. Poiché si sta effettuando la distribuzione su una coda asincrona, è possibile inserire una funzione sleep() dopo l'elaborazione di ogni 100 ° elemento. Questo dovrebbe ridurre la quantità di lavoro per il processore perché il thread si blocca per una certa percentuale del tempo, ma non renderà la tua interfaccia utente lenta, perché è solo una coda di sfondo.

Ovviamente questo sacrificherà il carico della CPU per il tempo di esecuzione.

1

Sembra che tu non stia facendo nulla per limitare il numero di operazioni simultanee. Fare questo probabilmente sarà più efficace del tentativo di limitare l'utilizzo della CPU poiché la limitazione dell'utilizzo della CPU è un concetto vago al confronto.

Per limitare il numero di operazioni simultanee, è possibile eseguire una delle seguenti operazioni:

  1. fare un dispatch_queue utilizzando dispatch_queue_create("com.myApp.loadQueue", DISPATCH_QUEUE_SERIAL). DISPATCH_QUEUE_SERIAL impedisce l'esecuzione contemporanea dei blocchi nella coda.

  2. Come @JoJoe menzionato nella risposta, utilizzare NSOperationQueue. Suggerirei di utilizzare setConcurrentOperationCount: anziché setThreadPriority: per limitare il numero di operazioni simultanee. Se non vuoi preoccuparti di configurare la sottoclasse NSOperation puoi usare NSBlockOperation.