2011-12-25 2 views
1

enumerateObjectsWithOptions:usingBlock 메서드를 사용하여 배열을 열거하려고합니다. 그러나 내 코드는 거의 작동하지 않습니다. 작동하지 않으면 내 앱이 멈 춥니 다 (해변 공이 없음). 저는 블록에 비교적 익숙하지 않으므로 블록 작업이 원활하게 작동하는 데 필요한 것을 놓치고 있어야합니다.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 블록을 추가해야했습니다.

+0

잠재적으로 폭발적인 동시성 알고리즘을 사용하고 있습니다. 지금은 효과가 있지만 너무 비효율적 일 수 있습니다. – bbum

+0

알았어 - 내가 어떻게 막을거야? 나는 열거의이 종류에 새롭다, 그래서 나는 너를 줄 수있는 어떤 통찰력을 주셔서 감사합니다! – Pripyat

답변

2

_cookies가 정의 된 곳이 보이지 않지만 NSMutableArray라고 가정 할 수 있습니다. 그것들은 스레드 세이프가 아니므로 동시에 여러 스레드가 읽고 해당 배열에 객체를 추가하는 경우 문제가 발생합니다.

해결 방법에는 여러 가지가 있습니다. 한 가지 옵션은 해당 배열을 소유하는 직렬 대기열을 만드는 것입니다. 처리 과정에서 쿠키를 확인 (필요할 경우 추가)해야 할 때마다 해당 작업을 수행 할 큐의 작은 블록을 예약하십시오. 그렇게하면 해당 읽기 및 추가가 엄격하게 연속되도록 할 수 있습니다.

여기에도 다른 아이디어가 있습니다.

그런데 한 걸음 뒤로 물러나면 그 스레드가 그 _cookies를 걷는 것을 막기 위해 그 춤을 소개하면 가장 효율적인 구현이라고 생각할 수도 있습니다. 실제 데이터로 테스트해야합니다.

왜 여기 NSOperation이 필요합니까? 어쨌든 결과를 기다리므로, 메인 큐에서 열거를 시작한 다음 거기에서 팬 아웃시키지 않는 이유는 무엇입니까? (뭔가 빠졌을 수 있습니다)

+0

NSOperation은 주 스레드가 오버로드되는 것을 방지합니다. 이 작업은 크기 때문에 이러한 작업을 주 대기열로 보내면 모든 작업이 잠길 수 있습니다. – Pripyat

+0

하지만 WaitUntilFinished를 대기하면 주 스레드가 차단됩니다. –

+0

당신은 정확했습니다 - 제 수업은 스레드로부터 안전하지 못했습니다. 올바른 자리에서'@ syncronized' 호출을 추가하면 내 문제가 해결되었습니다. – Pripyat

4

"내가 for 루프를 사용하고 있습니다"라고 말하면 for 루프가 동시에 실행 중이거나 효율적으로 선형으로 실행 중입니까?

해당 코드를 보면 블록 사용에 문제가 없습니다. 결론적으로 사용중인 API에 대한 완전한 지식 없이는 말할 수 없지만 해당 코드의 기본 알고리즘은 실제로 폭발적으로 병렬 인입니다.

즉, 각 루프는 가능한 한 동시에 물건을 시도하고 처리하도록 구성됩니다. 호출하는 API의 모든 비트가 스레드 안전 인 경우를 제외하고는 다중 스레드 충돌로 인해 코드가 충돌하거나 잠금 될 수 있습니다 (증상의 임의성은 동시성 문제의 확실한 징후입니다).

모든 API가 스레드 안전성이 있더라도 폭발적인 동시성은 올바른 동시성 모델이 아닙니다. 기껏해야, 동시성을 줄이기를 원할 것입니다. 당신은 일종의 메커니즘을 사용하여 동시에 처리되는 쓰레기의 양을 제한하려고합니다.

관련 문제