2016-08-07 3 views
2

나는이 방법IOS 스레드 풀

-(void)addObjectToProcess(NSObject*)object; 

있어 내가 병렬로 4 개의 물체를 처리 할 수있는 프로세스 큐에 객체를 추가하려면이 방법을 원한다.

난 내 자신의 dispatch_queue을 작성

_concurrentQueue = dispatch_queue_create([queue_id UTF8String],DISPATCH_QUEUE_CONCURRENT); 
_processSema = dispatch_semaphore_create(4); 

을 semhphore 및 방법의 구현은했습니다

-(void)addObjectToProcess(NSObject*)object { 
    dispatch_semaphore_wait(self.processSema, DISPATCH_TIME_FOREVER); 
    __weak MyViewController* weakSelf = self; 

    dispatch_async(self.concurrentQueue, ^{ 
     // PROCESS........... 
     // .................. 
     dispatch_semaphore_signal(self.processSema); 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      // call delegate from UI thread 
     }); 
    }); 
    } 

는 호출자가 때때로 세마포어 장벽의 차단 원인을 얻을 것 같다.

내가 여기 만들려고하는 것을 구현하는 다른/쉬운 옵션이 있습니까?

감사

+1

그런데 세마포어 문제 외에도 코드에는 두 가지 문제가 있습니다. 첫째,'weakSelf'는 당신이 원하는 것을 성취하지 못할 것입니다. 왜냐하면 클로저 내부에 참조 자체가 있기 때문에 View Controller에 대한 강력한 참조를 유지하기 때문입니다. 약한 참조는 아무에게도 해당되지 않습니다. 둘째로, closure 내부의 'self'참조를'weakSelf'로 대체하는 것만으로는 충분하지 않습니다. 왜냐하면 그것은 경쟁 조건을 도입하기 때문입니다. 클로저 안에 새로운'strongSelf' 레퍼런스를 만들어야합니다 ('self'를 참조하는 것이 아니라'weakSelf'에 대한 새로운 강력한 참조를 만드는 것입니다). – Rob

답변

3

문제는 당신이 (아마도 메인 스레드)에 addObjectToProcess를 붙인 스레드에서 dispatch_semaphore_wait를 호출하고 있다는 점이다. 따라서 네 개의 작업이 이미 실행중인 경우이 다섯 번째 프로세스를 예약하면 주 스레드에서 대기합니다.

세마포를 기다리는 블록을 self.concurrentQueue으로 옮기고 싶지는 않지만 "PROCESS"작업을 한 번에 4 개로 제한 할 수는 있지만 다른 작업자 스레드 이러한 백 로그 된 작업 각각에 대해 작업 스레드가 제한적으로 존재합니다. 그리고 그걸 다 써 버리면 다른 프로세스에 나쁜 영향을 줄 수 있습니다.

이 문제를 해결하는 방법 중 하나는 동시 처리 대기열과 함께 직렬 일정 대기열을 생성 한 다음이 전체 일정 예약 작업을이 예약 대기열에 비동기 적으로 전달하는 것입니다. 따라서 프로세스 대기열에서 최대 동시성을 누리지 만 메인 스레드를 차단하거나 백업 된 작업에 작업자 스레드를 사용하지 않습니다. 예를 들어 :

@property (nonatomic, strong) dispatch_queue_t schedulingQueue; 

그리고

self.schedulingQueue = dispatch_queue_create("com.domain.scheduler", 0); 

그리고

- (void)addObjectToProcess(NSObject*)object { 
    dispatch_async(self.schedulingQueue, ^{ 
     dispatch_semaphore_wait(self.processSema, DISPATCH_TIME_FOREVER); 
     typeof(self) __weak weakSelf = self; 

     dispatch_async(self.concurrentQueue, ^{ 
      // PROCESS........... 
      // .................. 
      typeof(self) __strong strongSelf = weakSelf; 
      if (strongSelf) { 
       dispatch_semaphore_signal(strongSelf.processSema); 
       dispatch_async(dispatch_get_main_queue(), ^{ 
        // call delegate from UI thread 
       }); 
      } 
     }); 
    }); 
} 

또 다른 좋은 방법 (이하 "PROCESS는"동기 특히 경우) 제어하는하는 maxConcurrentOperationCount을 가지고 그 NSOperationQueue을 사용하는 것입니다 동시성의 정도. 다음

self.processQueue = [[NSOperationQueue alloc] init]; 
self.processQueue.maxConcurrentOperationCount = 4; 

그리고 :

@property (nonatomic, strong) NSOperationQueue *processQueue; 

그리고 초기화 : 예를 들어

- (void)addObjectToProcess(NSObject*)object { 
    [self.processQueue addOperationWithBlock:^{ 
     // PROCESS........... 
     // .................. 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      // call delegate from UI thread 
     }); 
    }]; 
} 

유일한 트릭은 "PROCESS는"자체가 비동기 인 경우이다. 그렇게하면 addOperationWithBlock을 사용할 수없고 사용자 지정 비동기식 NSOperation 하위 클래스를 작성한 다음 을 NSOperationQueue에 사용해야합니다. 비동기식 NSOperation 서브 클래스를 작성하는 것은 어렵지 않지만 그와 관련된 몇 가지 작은 세부 사항이 있습니다. 동시성 프로 그래 V 안내서에서 Configuring Operations for Concurrent Execution을 참조하십시오.