2013-12-08 2 views
0

У меня проблема с моим приложением, где она накапливается до 100% использования ЦП при сборе данных. Я сделал все, о чем я могу думать, чтобы править в процессе обработки, чтобы он не блокировал устройство и все еще продолжает получать нужные данные.iOS Использование CPU skyrockets здесь

У наших клиентов есть несколько больших баз данных, поэтому загрузка всей базы данных не возникает. Мы также используем REMObjects в качестве промежуточного ПО, поэтому я должен работать с этим. То, что я сделал, это выяснить, какие данные необходимы пользователю, и настроить серию вызовов для сбора этой информации. Я думаю, что, где моя проблема заключается в том, что база данных может обрабатывать до 1500 элементов в вызове.

Ниже приведен пример строки запроса, отправляемой на сервер.

SELECT COMMUNICATIONID, PHONEEXTENTION, PHONEDESC, PHONETIMETOCALL, PHONENUMBER 
FROM PHONE WHERE COMMUNICATIONID IN (3761, 3793, 5530, 4957, 4320, 1914, 3715, 6199, 5548, 
5580, 5994, 5867, 1437, 4943, 6217, 3765, 2442, 227, 4084, 977, 6822, 5680, 263, 4502, 
327, 6112, 136, 7053, 5571, 6958, 6799, 5525, 6530, 4779, 604, 2182, 6198, 3792, 6071, 
4383, 5866, 7444, 1309, 226, 4083, 5916, 1295, 626, 1249, 1950, 2141, 3369, 326, 135, 
6780, 5411, 5938, 4424, 6034, 649, 6179, 5861, 4778, 5479, 2181, 6197, 3791, 5815, 6070, 
6420, 7935, 4542, 4319, 6679, 4942, 4082, 4974, 5533, 5788, 5597, 976, 3764, 1917, 6202, 
134, 6779, 3768, 5410, 5665, 7880, 7052, 6033, 5492, 6815, 3118, 4218, 5110, 6529, 6115, 
6069, 348, 4318, 4382, 1498, 6406, 4941, 7443, 2376, 4623, 5755, 5532, 6201, 6392, 625, 
7270, 4977, 6396, 6524, 5664, 7051, 725, 6032, 6701, 6160, 5491, 5937, 6273, 1875, 6114, 
5477, 6528, 5573, 4936, 6705, 2180, 3758, 5527, 5368, 5814, 7328, 7424, 429, 5991, 1434, 
6391, 6200, 7283, 5868, 5900, 228, 4085, 6109, 1106, 5791, 692, 6095, 7210, 2893, 1188, 
6814, 4217, 5572, 3757, 5813, 3694, 796, 605, 6486, 128, 4144, 5722, 5754, 1915, 5676, 
5549, 5581, 4976, 5917, 5822, 2174, 6158, 1633, 4566, 5267, 4885, 4503, 1874, 6113, 5476, 
4425, 4871, 5526, 6531, 7886, 1496, 5194, 127, 4780, 5721) 

Эта строка создается следующим методом, который затем асинхронно отправляет его на сервер. В этом методе есть одна проблема, которая, как я знаю, является проблемой, но у меня не было времени вернуться к ней и разработать лучшее решение. Я использую responsesToSelector и performSelector для обработки дополнительных методов на основе таблицы, с которой мы собираем данные.

- (void)processRequest 
{ 
    if(requestQueue.count == 0) 
     return; 

    if(processingQueue.count > 3) 
     return; 

    Request *request = requestQueue[0]; 
    [requestQueue removeObjectAtIndex:0]; 
    DADataTable *source = request.source; 
    NSString *destTableName = request.destTableName; 
    NSString *sourceKey = request.sourceKey; 
    NSString *query = request.query; 
    NSArray *destKeys = request.destKeys; 
    NSString *originMethodName = request.originMethodName; 
    NSArray *destinationMethods = request.destinationMethods; 
    NSString *message = request.loadingMessage; 

    [[NSNotificationCenter defaultCenter] postNotificationName:@"GATHERINGDATA" object:nil]; 


    // Cycle through the rows in the source table and extract the keys we need. 
    // originMethodName is needed because some tables require additional checks 
    // to determine what kind of key we are working with 
    // sourceKey is the string that holds the key we're looking for, which is 
    // used on tables that don't need specific filtering 
    NSSet *set = [self getSourceSet:source originMethodName:originMethodName sourceKey:sourceKey]; 

    // getLists takes the set generated by getSourceSet and converts the list of 
    // ids into a comma separated list of items suitable for passing into a query 
    // Currently there is a 1400 item limit per list to keep from exceeding the server 
    // limit, which is currently 1500 
    NSArray *lists = [self getLists:set]; 

    NSString *msg = @"Loading Data"; 
    NSLog(@"%@", message); 
    for(NSString *tList in lists) { 
     if(tList.length == 0) { 
      NSLog(@"%@ not needed", originMethodName); 
      continue; 
     } 

     query = [query stringByAppendingFormat:@"%@)", tList]; 

     NSLog(@"%@: %@", destTableName, query); 
     DAAsyncRequest __block *r = [fda beginGetDataTableWithSQL:query withBlock:^(DADataTable *table){ 
      DADataTable *destination = [tables valueForKey:destTableName]; 
      if(tables.count == 0) destination = table; 
      else if([destination rowCount] > 0) 
       //dispatch_async(queue, ^(){ 
       [destination mergeTable:table withPrimaryKeys:destKeys]; 
       //}); 

      else 
       destination = table; 

      [[NSUserDefaults standardUserDefaults] setValue:msg forKey:@"LoadingMessage"]; 
      [[NSNotificationCenter defaultCenter] postNotificationName:InitialViewControllerNotificationLoadingUpdate object:nil]; 
      [[NSNotificationCenter defaultCenter] postNotificationName:@"UpdateStatus" object:nil]; 

      //dispatch_async(queue, ^(){ 
      [tables setValue:destination forKey:destTableName]; 
      //}); 

      for(NSString *method in destinationMethods) { 
       SEL tMethod = NSSelectorFromString(method); 
       if([self respondsToSelector:tMethod]) { 
        [self performSelector:tMethod withObject:table]; 
       } 
      } 


      if([self busy] && 
       [[source name] isEqualToString:DataAccessTableCustomer]) 
      { 
       [[NSUserDefaults standardUserDefaults] setValue:nil forKey:@"FETCHINGJOB"]; 
       [[NSNotificationCenter defaultCenter] postNotificationName:@"JOBFETCHED" object:nil]; 
      } 
      if([[[NSUserDefaults standardUserDefaults] valueForKey:@"FETCHINGCONTACT"] isEqualToString:@"YES"] && 
       ([[source name] isEqualToString:DataAccessTablePerson] || 
       [[source name] isEqualToString:DataAccessTableOrganization] || 
       [[source name] isEqualToString:DataAccessTableOrganizationAddress])) 
      { 
       [[NSUserDefaults standardUserDefaults] setValue:nil forKey:@"FETCHINGCONTACT"]; 
       [[NSNotificationCenter defaultCenter] postNotificationName:@"CONTACTFETCHED" object:nil]; 
      } 
      [processingQueue removeObject:r]; 
      [[NSNotificationCenter defaultCenter] postNotificationName:@"PROCESSREQUEST" object:nil]; 
     }]; 
     [processingQueue addObject:r]; 
    } 
} 

Любая помощь здесь будет принята с благодарностью! Спасибо, что нашли время посмотреть.

+1

Нам нужна дополнительная информация, которая вам поможет. Запускаете ли вы свой код с помощью инструмента профилирования времени? Это укажет вам на код, который занимает наибольшее время процессора. –

ответ

1

Наличие вашего процессора до 100% не обязательно является плохим. На устройстве с несколькими ядрами (iPhone 4 и более поздние) загрузка процессора на 100% превышает количество ядер. Таким образом, максимум 4s составляет 200%, а на 5s - 400%.

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

Вы видите лагинг-интерфейс? Это то, что вы должны использовать в качестве своего датчика, что вам нужно улучшить.

Мое предложение состояло в том, чтобы переписать свой код для запуска в фоновом режиме GCD. Сначала попробуйте приоритет по умолчанию (тот же приоритет, что и пользовательский интерфейс.) На многоядерной машине, которая будет связывать один из ядер. На iPhone 4, однако, это может сделать UI лагги. В этом случае вы можете перейти к следующему более низкому приоритету, который заставит его заняться больше времени, но при этом будет иметь более высокий приоритет для пользовательского интерфейса.

Затем вы можете оптимизировать код при необходимости. Пользовательские настройки по умолчанию - это не самый эффективный способ обработки данных состояния в цикле. Вы можете попытаться удалить вызовы по умолчанию для пользователей и переключиться на сохранение данных в переменной экземпляра или, в контейнере данных singleton, если вам нужно передать информацию между объектами. Кроме того, NSNotificationCenter имеет больше накладных расходов, чем вызовы делегатов, блокирует вызовы или вызовы простых методов.

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

+0

Я собираюсь задать другой вопрос, потому что именно эти петли заставляют пользовательский интерфейс зависать, но потом возникают другие проблемы. Спасибо, что встретил меня на правильном пути. Я не знал об использовании процессора против Core. – arythiafan

2

Да. В основном золотое правило: do not optimize prematurely.

Но так или иначе. Мое первое предположение было бы: заменить NSString query на NSMutableString query. Поскольку вы создаете 1500 объектов NSString в куче, всегда увеличивая длину, просто выбросьте их в следующем цикле. NSMutalbeString сохраняет память в течение более длительного времени при добавлении - и вы всегда разговариваете с одним и тем же объектом. '(Затем используйте appendFormat без повторного назначения вместо stringByAppendingFormat с назначением!)

Оставить заявку: Is NSMutableString's -appendString: method an efficient way to build up a large string?

+0

Хорошая точка. Использование изменчивых строк значительно уменьшит обрыв памяти внутри цикла. Также может быть хорошей идеей добавить директиву @autoreleasepool вокруг итерации внешнего цикла, чтобы очистить временные объекты. Тем не менее, я думаю, что главное - выполнить пакетную обработку в фоновом режиме (используя GCD), чтобы он не останавливал пользовательский интерфейс. –

Смежные вопросы