Задача-c, как пакетировать несколько операций чтения
Я выполняю несколько операций чтения на одном и том же ресурсе, хранящемся на диске.
Иногда сама операция чтения занимает больше времени, чем время между запросами к тому же ресурсу. В этих случаях имеет смысл объединить операции чтения в один запрос на чтение с диска и затем вернуть один и тот же результат различным запросчикам.
Первоначально я пытался кэшировать результат из исходного запроса на выборку ресурса - но это не сработало, потому что время, затрачиваемое на чтение ресурса, было слишком длинным, и приходили новые запросы - это означало, что они также будут пытаться получить ресурс.
Можно ли "добавить" дополнительные запросы к тем, которые уже выполняются?
Код, который у меня есть, теперь следует этой базовой структуре (которая недостаточно хороша):
-(void)fileForKey:(NSString *)key completion:(void(^)(NSData *data) {
NSData *data = [self.cache threadSafeObjectForKey:key];
if (data) {
// resource is cached - so return it - no need to read from the disk
completion(data);
return;
}
// need to read the resource from disk
dispatch_async(self.resourceFetchQueue, ^{
// this could happen multiple times for the same key - because it could take a long time to fetch the resource - all the completion handlers should wait for the resource that is fetched the first time
NSData *fetchedData = [self fetchResourceForKey:key];
[self.cache threadSafeSetObject:fetchedData forKey:key];
dispatch_async(self.completionQueue, ^{
completion(fetchedData);
return;
});
});
}
1 ответ
Я думаю, что вы хотите ввести вспомогательный объект
@interface CacheHelper{
@property (nonatomic, copy) NSData *data;
@property (nonatomic, assign) dispatch_semaphore_t dataReadSemaphore;
}
Ваш метод чтения теперь становится чем-то вроде
CacheHelper *cacheHelper = [self.cache threadSafeObjectForKey:key]
if (cacheHelper && cacheHelper.data)
{
completion(cacheHelper.data);
return;
}
if (cacheHelper)
{
dispatch_semaphore_wait(cacheHelper.dataReadSemaphore, DISPATCH_TIME_FOREVER);
dispatch_semaphore_signal(cacheHelper.dataReadSemaphore);
completion(cacheHelper.data)
return;
}
cacheHelper = [[CacheHelper alloc] init]
cacheHelper.dataReadSemaphore = dispatch_semaphore_create(0);
cacheHelper.data = [self fetchResourceForKey:key];
[self.cache threadSafeSetObject:cacheHelper forKey:key];
dispatch_semaphore_signal(cacheHelper.dataReadSemaphore);
completion(cacheHelper.data)
Это не скомпилированный код, поэтому, пожалуйста, проверьте орфографию и логику, но я надеюсь, что это объясняет идею. Мне нравится этот пост, если вы хотите познакомиться с семафорами.