#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. Тем не менее, я использовал вашу идею, чтобы убедиться, что рендеринг данных улучшен. Это помогло! Итак, я принимаю ваш ответ. Спасибо.