dispatch_async 이해


233

이 코드와 관련하여 질문이 있습니다.

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSData* data = [NSData dataWithContentsOfURL: 
      kLatestKivaLoansURL];
    [self performSelectorOnMainThread:@selector(fetchedData:) 
      withObject:data waitUntilDone:YES];
});

이 코드의 첫 번째 매개 변수는

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 

주어진 우선 순위 레벨의 글로벌 동시 큐를 리턴한다는 정의 자체의 글로벌 큐에서 직렬 태스크를 수행하도록이 코드를 요청합니까?

dispatch_get_global_queue메인 큐 를 사용할 때의 이점은 무엇입니까 ?

혼란 스러워요. 이것을 더 잘 이해하도록 도와주십시오.


1
코드를 여러 줄로 잘 잘라서 이해하는 것이 좋습니다. dispatch_get_global_queue변수 유형의 내부를 보호하십시오 dispatch_queue_t myQueue. myQueue 만을 ``dispatch_async ''로 전달 하는 것이 더 읽기 쉽습니다.
Alex Cio

답변:


517

기본 대기열에서 기본 대기열을 사용하는 주된 이유는 백그라운드에서 작업을 실행하기위한 것입니다.

예를 들어 인터넷에서 파일을 다운로드하고 다운로드 진행 상황에서 사용자를 업데이트하려는 경우 우선 순위 기본 대기열에서 다운로드를 실행하고 기본 대기열의 UI를 비동기식으로 업데이트합니다.

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    //Background Thread
    dispatch_async(dispatch_get_main_queue(), ^(void){
        //Run UI Updates
    });
});

데이빗은 귀하의 답변에 감사드립니다. 그러나 제 질문은이 작업을 수행하는 논리를 이해하는 데 더 도움이되었습니다. 즉,이 코드를 요청하여 동시 큐 자체 인 글로벌 큐에서 직렬 작업을 수행하도록 요청합니다
user2332873

UI 제안 실행에서 [self.tableView reloadData]를 호출해도 uiTableViewCell이 바로 업데이트되지 않습니다. 4 ~ 5 초 정도 걸립니다. 며칠 동안 미치게되었습니다. .
GrandSteph

@ GrandSteph 그 방법에 익숙하지 않습니다. 어쩌면 그 방법을 실행하는 데 5 초가 걸릴 수도 있습니다. dispatch_async의 중요한 점은 메인 스레드를 걸지 않고 백그라운드에서 작업을 수행 할 수 있다는 것입니다.
David

2
무엇을 0의미합니까?
Honey

3
@Honey 0은 flags현재 절대적으로 아무 것도 수행하지 않는 매개 변수입니다. 문서에서 :Flags that are reserved for future use. Always specify 0 for this parameter.
David

199

모든 DISPATCH_QUEUE_PRIORITY_X 대기열은 동시 대기열 (한 번에 여러 작업을 실행할 수 있음을 의미 함)이며 주어진 대기열 내의 작업이 "선입 선출"순서로 실행되기 시작한다는 의미에서 FIFO입니다. 이것은 직렬 대기열 인 dispatch_get_main_queue ()의 메인 대기열과 비교됩니다 (작업은 수신 된 순서대로 실행이 시작되고 실행이 완료 됨).

따라서 1,000 개의 dispatch_async () 블록을 DISPATCH_QUEUE_PRIORITY_DEFAULT로 전송하면 해당 작업이 대기열로 전송 된 순서대로 실행이 시작됩니다. HIGH, LOW 및 BACKGROUND 대기열도 마찬가지입니다. 이러한 대기열로 보내는 것은 기본 응용 프로그램 스레드와는 별도로 대체 스레드의 백그라운드에서 실행됩니다. 따라서 이러한 대기열은 백그라운드 다운로드, 압축, 계산 등과 같은 작업을 실행하는 데 적합합니다.

실행 순서는 큐마다 FIFO입니다. 따라서 1000 개의 dispatch_async () 작업을 4 개의 서로 다른 동시 대기열로 전송하고, 균등하게 분할하여 BACKGROUND, LOW, DEFAULT 및 HIGH로 순서대로 전송하면 (즉, HIGH 대기열에서 마지막 250 개의 작업을 예약) 가능성이 높습니다. 시스템이 해당 작업이 가능한 한 빨리 CPU에 도달해야 함을 암시함에 따라 시작하는 첫 번째 작업은 해당 HIGH 대기열에있게됩니다.

또한 "순서대로 실행을 시작하겠습니다"라고 말하지만 동시 대기열이므로 각 작업의 시간 길이에 따라 순서대로 완료가 반드시 완료되는 것은 아닙니다.

Apple에 따라 :

https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

동시 디스패치 큐는 병렬로 실행할 수있는 여러 태스크가있는 경우 유용합니다. 동시 대기열은 작업을 선입 선출 순서로 대기열에서 제외한다는 점에서 여전히 대기열입니다. 그러나 동시 큐는 이전 작업이 완료되기 전에 추가 작업을 대기열에서 제외시킬 수 있습니다. 주어진 순간에 동시 대기열에 의해 실행되는 실제 작업 수는 가변적이며 응용 프로그램의 조건이 변경되면 동적으로 변경 될 수 있습니다. 사용 가능한 코어 수, 다른 프로세스에 의해 수행되는 작업량, 다른 직렬 디스패치 큐의 작업 수 및 우선 순위를 포함하여 많은 요소가 동시 큐에서 실행되는 작업 수에 영향을줍니다.

기본적으로 1000 dispatch_async () 블록을 DEFAULT, HIGH, LOW 또는 BACKGROUND 대기열로 보내면 전송 순서대로 모두 실행되기 시작합니다. 그러나 더 짧은 작업은 더 긴 작업보다 먼저 완료 될 수 있습니다. 그 이유는 사용 가능한 CPU 코어가 있거나 현재 대기열 작업이 계산적으로 비 집약적 작업을 수행하는 경우입니다 (따라서 시스템이 코어 수에 관계없이 추가 작업을 병렬로 디스패치 할 수 있다고 생각하게 함).

동시성 수준은 시스템에서 전적으로 처리하며 시스템로드 및 기타 내부적으로 결정된 요소를 기반으로합니다. 이것이 Grand Central Dispatch (Dispatch_async () 시스템)의 아름다움입니다. 작업 단위를 코드 블록으로 만들고 우선 순위 (선택한 대기열을 기준으로)를 설정하고 나머지는 처리하도록합니다.

위의 질문에 대답하려면 부분적으로 맞습니다. 지정된 우선 순위 레벨에서 글로벌 동시 큐에서 동시 태스크를 수행하도록 "해당 코드 요청"입니다. 블록의 코드는 백그라운드에서 실행되며 사용 가능한 리소스에 대한 시스템의 평가에 따라 추가 (유사한) 코드가 잠재적으로 병렬로 실행됩니다.

반면에 "main"대기열 (dispatch_get_main_queue ()에서)은 직렬 대기열 (동시 아님)입니다. 기본 대기열로 전송 된 작업은 항상 순서대로 실행되며 항상 순서대로 완료됩니다. 이 작업은 UI 스레드에서도 실행되므로 진행 메시지, 완료 알림 등으로 UI를 업데이트하는 데 적합합니다.


+1이지만 실제로 동시 큐가 FIFO인지 또는 임의 순서인지는 중요하지 않습니다. 루프에서 5 개의 작업을 시작하면 기본적으로 동시에 시작한다고 가정합니다. 예를 들어 첫 번째 작업의 첫 번째 I / O 작업이 동일한 코드를 실행하더라도 5 일 전에 발생한다는 보장은 없습니다. 직렬 큐의 경우 OTOH의 경우 FIFO 동작이 필수적이며 IMHO는 두 큐 유형 간의 차이점을 정의합니다.
Gerhard Wesp

놀라운 설명. 많이 박수!
Okhan Okbay

36

스위프트 버전

이것은 David의 Objective-C 답변의 Swift 버전입니다. 글로벌 큐를 사용하여 백그라운드에서 작업을 실행하고 기본 큐를 사용하여 UI를 업데이트합니다.

DispatchQueue.global(qos: .background).async {
    
    // Background Thread
    
    DispatchQueue.main.async {
        // Run UI Updates
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.