Подтвердить что ты не робот

Использование процессора дроссельной заслонки в фоновом потоке

У меня есть задача с интенсивным процессором, и я хочу, чтобы он использовал меньше CPU и занимал больше времени.

Я загружаю огромное количество SCNNodes в сцену при запуске. Он занимает много памяти, и я бы хотел, чтобы он работал над ним с надежной скоростью, вместо того, чтобы отставать от моей системы или потенциально ее сбрасывать.

Вот код, который я использую для загрузки узлов.

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

Вот статистика:

Image Usage over TimeImage Memory

4b9b3361

Ответ 1

Это может быть не лучший способ сделать это, но посмотрели ли вы на prepareobject:?

Создание самих NSObjects не должно быть такой большой проблемой, но, возможно, подготовка геометрии и добавление ее в сцену. Bu, дефрагментируя этот шаг во вторичном потоке, вы сэкономите некоторый процессор и сделайте сцену не остановленной до тех пор, пока node не будет готова к добавлению.

Как только каждый node готов, (обработчик завершения) просто добавьте его в сцену. Я не буду дросселировать загрузку, но она, по крайней мере, будет обрабатывать ее более безопасно для остальной части вашего приложения.

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

Две идеи:

  • Используйте NSOperationQueue, у него есть метод setThreadPriority: который можно использовать для дросселирования нагрузки до некоторой степени.

  • Поскольку вы отправляете асинхронную очередь, возможно, вы можете вставить функцию sleep() после обработки каждого 100-го элемента или около того. Это должно сократить объем работы для процессора, потому что поток задерживается на некоторый процент времени, но он не сделает ваш пользовательский интерфейс лагги, потому что его просто фоновая очередь.

Очевидно, что это принесет жертве загрузку процессора за время выполнения.

Ответ 3

Похоже, вы ничего не делаете, чтобы ограничить количество одновременных операций. Выполнение этого, вероятно, будет более эффективным, чем попытка дросселировать использование ЦП, поскольку дросселирование использования процессора является неопределенной концепцией путем сравнения.

Чтобы ограничить количество одновременных операций, вы можете выполнить одно из следующих действий:

  • Создайте собственный dispatch_queue с помощью dispatch_queue_create("com.myApp.loadQueue", DISPATCH_QUEUE_SERIAL). DISPATCH_QUEUE_SERIAL предотвращает запуск блоков в очереди.

  • Как указано в их ответе @JoJoe, используйте NSOperationQueue. Я бы предложил использовать setConcurrentOperationCount:, а не setThreadPriority:, чтобы ограничить количество параллельных операций. Если вы не хотите беспокоиться о настройке собственного подкласса NSOperation, вы можете использовать NSBlockOperation.