enumerateObjectsWithOptions:usingBlock:导致频繁的无法解释的冻结

时间:2011-12-25 15:33:55

标签: objective-c cocoa concurrency nsarray objective-c-blocks

我正在尝试使用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 个答案:

答案 0 :(得分:4)

当你说“我正在使用for循环并且它有效”时,你的意思是你的for循环是同时运行还是它们有效地线性运行?

查看该代码,使用块没有任何问题。虽然如果不完全了解您正在使用的API,就无法确切地说,该代码中的基础算法实际上是爆炸性并行

也就是说,每个循环都配置为尽可能多地尝试和处理内容。除非您调用的API的每一位都是线程安全的,否则您的代码可能会因为多线程冲突而崩溃和/或锁定(症状的随机性是并发问题的明确标志)。

即使所有API都是线程安全的,爆炸性并发也绝不是正确的并发模型。充其量,你会想要限制并发;你想使用某种机制来限制同时处理的垃圾量。

答案 1 :(得分:2)

我不知道_cookies的定义在哪里,但我想我们可以假设它是一个NSMutableArray。那些不是线程安全的,所以如果你有多个线程读取并同时向该数组添加对象,那就是一个问题。

有不同的方法可以解决这个问题。一种选择是创建拥有该数组的串行队列。在处理过程中,每次需要检查(如果需要添加)cookie时,在该队列上安排一个小块来完成这项工作。这样你就可以确保那些读取和添加都是严格连续的。

当然,还有其他一些想法。

然后退后一步,一旦你引入那种舞蹈以防止线程跨越那些_cookies,你可能会或可能不会发现这是最有效的实现。您需要使用实际数据对其进行测试。

另外,为什么NSOperation在这里?既然你无论如何等待结果,为什么不开始主队列上的枚举然后让它从那里扇出来呢? (我可能会遗漏一些东西)