Не удалось повысить скорость работы приложения IOS с помощью Grand Central dispatch

#ios #ios7 #concurrency #grand-central-dispatch #ios7.1

#iOS #ios7 #параллелизм #grand-central-dispatch #ios7.1

Вопрос:

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

 dispatch_async(myBackgroundQueue, ^(void) {

            // do some time consuming things here
            [self queryForHiking: ulLat ulLong:ulLon lrLat:lrLat lrLong:lrLon];

            dispatch_async(dispatch_get_main_queue(), ^{

                // do some things here in the main queue
                // for example: update UI controls, etc.
                [self drawOnMap];
            });
        });
  

Как и в приведенном выше блоке кода, у меня есть 5 таких блоков. Функция drawOnMap рисует маршруты и траектории, сформированные на карте. Но для отображения всех путей (из разных запросов) на карте требуется много времени. Особенно при более высоком уровне масштабирования, когда требуется отобразить больше данных, приложение зависает, и для возобновления работы и отображения данных требуется много времени. Как я могу сделать это эффективным?

РЕДАКТИРОВАТЬ: я думаю, что запрос здесь занимает много времени, и у меня есть 5 таких запросов, которые независимы друг от друга. Ниже приведена одна из моих пяти функций запроса:

  - (void)queryForHikingTrails:(NSString*)ulLat ulLong:(NSString*)ulLong lrLat:(NSString*)lrLat lrLong:(NSString*)lrLong
 {
     @try {
         [_db inDatabase:^(FMDatabase *db) {

             FMResultSet *trails = [db executeQueryWithFormat:@"SELECT ID2,Latitude, Longitude FROM hikingtrails WHERE Latitude BETWEEN %@ and %@ AND Longitude BETWEEN %@ and %@", lrLat, ulLat, lrLong, ulLong];

             hikingTrails = [self buildTrails:trails];
         }];
     }
     @catch (NSException *e) {
         NSLog(@"Error Querying for Trails: %@ - %@", [e name], [e reason]);
     }
     @finally {
     }
 }
  

Ниже приведено время, затраченное на выполнение только этого запроса (пеший туризм):

Время, затраченное на запрос: 0,053462 Время, затраченное функцией перерисовки (drawOnMap) = 0,000008

Когда я запускаю два запроса (пеший туризм некоторые другие маршруты):

Время, затраченное на запрос: 2,681138 Время, затраченное функцией перерисовки (drawOnMap) = 0,000010

У меня нет привилегии каким-либо образом изменять базу данных. т. Е. я не могу разделить таблицу или нормализовать ее.

База данных состоит примерно из 18000 записей только для походов, которые вышеуказанная функция пытается запросить.

Есть ли какой-либо способ помимо применения оптимизации базы данных для ускорения запросов, по крайней мере, запускать их в фоновом режиме одновременно (все 5)?

РЕДАКТИРОВАТЬ: я провел дальнейшее расследование и обнаружил, что только один запрос занимает много времени (11.7834), в то время как другие не занимают много времени. Как я должен обрабатывать этот конкретный запрос? Есть ли способ, с помощью которого я могу выполнить этот запрос в фоновом режиме, не блокируя просмотр карты. Я не знаю, как это будет возможно, потому что каждый раз, когда выполняется этот запрос, mapview обновляется функцией drawOnMap. Пожалуйста, направьте меня.

Комментарии:

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

2. @erikprice-Я обновил вопрос.

3. Это вроде как неправильно, @erikprice, вы не думаете , что что-то занимает много времени. Вы измеряете это. Вставьте код синхронизации (сравнение с NSDate может подойти) и сначала выясните, что является узким местом. Измерьте, сколько времени занимает загрузка базы данных по сравнению с рисованием пользовательского интерфейса, затем оптимизируйте самый медленный. Затем повторяйте до тех пор, пока не будет удовлетворено. Для SQL у вас есть индексы или разделение таблиц, для рисования у вас есть тайлинг.

4. @GrzegorzAdamHankiewicz-Я обновил вопрос с учетом затраченного времени и обнаружил, что запрос является узким местом.

5. @GrzegorzAdamHankiewicz Я в замешательстве; я что-то говорил о том, что для обдумывания чего-то требуется много времени?

Ответ №1:

Я не уверен, что подход, который я предлагаю ниже, работает для вас, но, возможно, он может быть полезен. Он использует очередь операций для одновременного выполнения ваших запросов, и только когда все они завершены, он вызывает -[self drawOnMap] . Однако, чтобы оно работало правильно, каждый из ваших запросов должен блокировать текущий поток. Из вашего исходного кода на основе GCD я сделал вывод, что это так. Но это также предполагает, что ваши методы запроса могут выполняться одновременно в безопасности (например, что все, что вы делаете с результатами запроса, может быть безопасно выполнено из нескольких потоков).

Зависимости NSOperation дают вам простой способ указать, что работа может выполняться одновременно, а затем выполнить одно окончательное обновление, когда эта работа будет завершена:

 self.queryQueue = [[NSOperationQueue alloc] init];

NSBlockOperation *queriesOperation = [NSBlockOperation blockOperationWithBlock:^{
    [self queryForHiking:ulLat ulLong:ulLon lrLat:lrLat lrLong:lrLon];
}];
[queriesOperation addOperation:^{
    [self performSomeOtherQuery];
}];
[queriesOperation addOperation:^{
    [self performYetAnotherQuery];
}];
// do this for each of your queries

NSOperation *drawOperation = [NSBlockOperation blockOperationWithBlock:^{
    [self drawOnMap];
}];
[drawOperation addDependency:queriesOperation];

[self.queryQueue addOperation:queriesOperation];
[NSOperationQueue.mainQueue addOperation:drawOperation];
  

Комментарии:

1. Хотя проблема оказалась в неэффективном запросе SQL join. Тем не менее, я использовал вашу идею, чтобы убедиться, что рендеринг данных улучшен. Это помогло! Итак, я принимаю ваш ответ. Спасибо.