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

发布于 2024-12-22 23:18:55 字数 2103 浏览 7 评论 0原文

我尝试使用 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 块才能使其按预期工作。

I'm trying to enumerate through arrays using the enumerateObjectsWithOptions:usingBlock method. However, my code rarely works. When it does not work, my app freezes (but no beach ball) -- I'm relatively new to blocks, so I must be missing something that is required for block operations to work smoothly.

Note: I know I can enumerate using for loops, but this is not what I am looking for.

The troublesome code:

   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

Edit

I have fixed it. You were right, my class was not thread safe. So I had to add an @synchronized block for this to work as expected.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小糖芽 2024-12-29 23:18:55

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

看看这段代码,使用块没有任何问题。虽然在不完全了解您正在使用的 API 的情况下不可能得出结论,但该代码中的底层算法实际上是爆炸性并行

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

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

When you say "I'm using for loops and it works", do you mean that your for loops are running concurrently or that they are, effectively, running linearly?

Looking at that code, there is nothing wrong with the use of blocks. While it is impossible to conclusively say without full knowledge of the APIs you are using, the underlying algorithm in that code is effectively explosively parallel.

That is, each of your loops is configured to try and process stuff concurrently as much as possible. Unless every bit of the API you are calling is thread safe, then your code is likely crashing and/or locking up (the randomness of the symptoms are a sure sign of concurrency issues) because of multi-threaded conflicts.

Even if all the APIs are thread safe, explosive concurrency is pretty much never the right concurrency model. At best, you'll want throttled concurrency; you want to use some kind of a mechanism to limit the amount of junk being processed concurrently.

几味少女 2024-12-29 23:18:55

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

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

当然还有其他的想法。

但退一步来说,一旦您引入了这种舞蹈来防止线程遍历这些 _cookie,您可能会发现也可能不会发现这是最有效的实现。您需要用实际数据进行测试。

另外,为什么在这里使用 NSOperation ?既然你无论如何都要等待结果,为什么不在主队列上启动枚举,然后让它从那里散开呢? (我可能遗漏了一些东西)

I don't see where _cookies is defined, but I guess we can assume it is an NSMutableArray. Those are not threadsafe, so if you have multiple threads reading and also adding objects to that array at the same time, that is a problem.

There are different ways to solve that. One option is to create a serial queue that owns that array. In the course of your processing, each time you need to check for (and if needed add) a cookie, schedule a small block on that queue to do that work. That way you can ensure those reads and adds are strictly serial.

There are other ideas for this also of course.

But then taking a step back, once you introduce that dance to keep the threads from stepping all over those _cookies, you may or may not find this is the most efficient implementation. You'll need to test that with your actual data.

Also, why the NSOperation here? Since you wait for the results anyway, why not just kick off the enumeration on the main queue and then let it fan out from there? (I may be missing something)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文