enumerateObjectsWithOptions: usingBlock: вызывает частые необъяснимые зависания - PullRequest
1 голос
/ 25 декабря 2011

Я пытаюсь перечислить через массивы, используя метод enumerateObjectsWithOptions:usingBlock.Однако мой код редко работает.Когда это не работает, мое приложение зависает (но не играет в пляжный мяч) - я относительно новичок в блоках, поэтому мне, должно быть, не хватает чего-то, что требуется для плавной работы блоков.

Примечание: Я знаю, что могу перечислять, используя for циклы, но это не то, что я ищу.

Неудобный код:

   NSArray*_storageCookies = [[NSArray alloc] initWithArray:[storage cookies]];

    NSArray*_historyObjects = [[NSArray alloc] initWithArray:[_history webkitHistory]];

    NSOperationQueue*_queue = [[NSOperationQueue alloc] init];

    NSBlockOperation*_block = [NSBlockOperation blockOperationWithBlock:^{

        NSAutoreleasePool*_pool = [[NSAutoreleasePool alloc] init];

        [_storageCookies enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id ck, NSUInteger index, BOOL *stop) 
        {            
            NSString*domain = [ck domain];

            [_historyObjects enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id object, NSUInteger aindex, BOOL *stop) 
            {
               @synchronized(self)
               {
                NSAutoreleasePool*_pool2 = [[NSAutoreleasePool alloc] init];

                NSString*_historyURL = [[NSURL URLWithString:[object url]] host];

                if ([_historyURL rangeOfString:domain].location != NSNotFound)
                {
                    NSHTTPCookie*cookie = [DAHTTPCookie createCookieWithURL:[ck domain] cookieName:[ck name] expires:[[ck expiresDate] timeIntervalSince1970] cookieValue:[ck value] browserType:DAWebkitBrowser secure:[ck isSecure]];

                    if ([_cookies containsObject:cookie] == NO)
                    {
                        [_cookies addObject:cookie];
                    }
                }

                [_pool2 release];
}
             }];
        }];

        [_pool release];
    }];

    [_queue addOperations:[NSArray arrayWithObject:_block] waitUntilFinished:YES];

    NSLog(@"Done - found %i Cookies...",[_cookies count]); //sometimes returns 0, sometimes the right number or nothing

Редактировать

Я исправил это.Вы были правы, мой класс не был безопасен.Поэтому мне пришлось добавить блок @synchronized, чтобы он работал как положено.

Ответы [ 2 ]

4 голосов
/ 25 декабря 2011

Когда вы говорите: «Я использую для циклов, и это работает», вы имеете в виду, что ваши циклы for работают одновременно или что они, по сути, работают линейно?

Глядя на этот код, нет ничего плохого в использовании блоков. Хотя невозможно окончательно сказать без полного знания используемых вами API, основной алгоритм в этом коде фактически взрывно параллельный .

То есть каждый из ваших циклов настроен на одновременную обработку и обработку данных в максимально возможной степени. Если каждый вызываемый вами API-интерфейс не является поточно-ориентированным, то ваш код, скорее всего, аварийно завершает работу и / или блокируется (случайность симптомов является явным признаком проблем параллелизма) из-за многопоточных конфликтов.

Даже если все API-интерфейсы являются поточно-ориентированными, взрывной параллелизм почти никогда не является правильной моделью параллелизма. В лучшем случае вам нужен ограниченный параллелизм; Вы хотите использовать какой-то механизм для ограничения количества мусора, обрабатываемого одновременно.

2 голосов
/ 25 декабря 2011

Я не вижу, где определяется _cookies, но я думаю, мы можем предположить, что это NSMutableArray.Они не являются поточно-ориентированными, поэтому, если у вас есть несколько потоков, считывающих и добавляющих объекты в этот массив одновременно, это проблема.

Существуют различные способы решения этой проблемы.Один из вариантов - создать последовательную очередь, которой принадлежит этот массив.В процессе обработки каждый раз, когда вам нужно проверить (и при необходимости добавить) файл cookie, запланируйте небольшой блок в этой очереди, чтобы выполнить эту работу.Таким образом, вы можете убедиться, что эти операции чтения и добавления являются строго последовательными.

Есть и другие идеи для этого, конечно.

Но затем сделайте шаг назад, как только вы представите этот танец, чтобы сохранитьЕсли вы не будете обходить все эти _cookies, вы можете найти или не найти это наиболее эффективную реализацию.Вам нужно будет проверить это с вашими фактическими данными.

Кроме того, почему здесь NSOperation?Так как вы все равно ждете результатов, почему бы просто не запустить перечисление в главной очереди, а затем дать ему развернуться оттуда?(Я могу что-то упустить)

...