2013-12-08 21 views
0

我的應用程序出現問題,收集數據時,CPU使用率高達100%以上。我已經盡了我所能想到的處理方式,以便它不鎖定設備,並且仍然繼續獲取所需的數據。iOS CPU使用率在這裏上升

我們的客戶有一些大的數據庫,所以下載整個數據庫是不成問題的。我們也使用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) 

該字符串是通過以下的方法,其接着發送它異步於服務器創建的。這種方法存在一個問題,我知道這是一個問題,但我沒有時間回過頭來設計一個更好的解決方案。我正在使用respondsToSelector和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

我們需要更多的信息來幫助你。你有沒有使用時間分析器儀器運行你的代碼?這會指向佔用最多CPU時間的代碼。 –

回答

1

讓您的CPU達到100%以上並不一定是壞事。在具有多個內核的設備(iPhone 4s和更高版本)上,CPU利用率是內核數量的100%。所以最大4s是200%,5s是400%。

在循環中執行一堆處理會最大化該線程上的CPU使用率,因爲代碼將全速運行直至完成。這是正常的和適當的。

您是否看到laggy UI性能?這就是你應該用來衡量你需要改進的地方。

我的建議是重寫你的代碼在GCD背景隊列上運行。首先嚐試默認優先級(與UI相同的優先級)。在多核機器上,這將綁定其中一個內核。但是,在iPhone 4上,它可能會使UI變得遲鈍。在這種情況下,您可以切換到下一個較低的優先級,這會花費更長的時間,但給用戶界面提供更高的優先級。

如果需要,您可以優化您的代碼。用戶默認不是在循環中處理狀態數據的最有效方式。您可以嘗試刪除用戶默認值調用並切換到保存實例變量中的數據,或者在數據容器單例中,如果需要在對象之間傳遞信息。另外NSNotificationCenter比委託調用,塊調用或簡單的方法調用具有更多開銷。

但是,我不會擔心這些事情,直到你確定需要優化。

+0

我要問另外一個問題,因爲這是導致用戶界面掛起的循環,但後來我遇到了其他問題。感謝您讓我在正確的軌道上。我不知道有關CPU使用率與核心。 – 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),所以它不會拖延用戶界面。 –