iPhone-그랜드 센트럴 디스패치 메인 스레드


145

내 앱에서 성공적으로 중앙 집중식 디스패치를 ​​사용했지만 다음과 같은 것을 사용하면 실제로 어떤 이점이 있는지 궁금합니다.

dispatch_async(dispatch_get_main_queue(), ^{ ... do stuff

또는

dispatch_sync(dispatch_get_main_queue(), ^{ ... do stuff

두 가지 경우 모두 메인 스레드에서 실행될 블록을 실행하는 것입니다. 앱이 실행되는 정확한 위치이며로드를 줄이는 데 도움이되지 않습니다. 첫 번째 경우 블록이 실행될 때 제어 할 수 없습니다. 블록을 발사 한 후 0.5 초 동안 블록이 실행되는 경우를 보았습니다. 두 번째 경우는

[self doStuff];

권리?

나는 당신들이 어떻게 생각하는지 궁금합니다.


9
그건 그렇고, 메인 큐를 dispatch_sync에 던지면 교착 상태가 발생합니다.
Brooks Hanes

5
"dispatch_async와 달리 [dispatch_sync]는 블록이 완료 될 때까지 반환되지 않습니다.이 함수를 호출하고 현재 대기열을 대상으로하면 교착 상태가 발생합니다." 현재 큐는 메인 스레드를 의미하지 않습니다). 내가 틀렸다면 정정하십시오.
Brooks Hanes

4
@BrooksHanes가 항상 사실은 아닙니다. 이미 주 스레드에 있으면 교착 상태가 발생합니다 . 그렇지 않으면 교착 상태가 발생하지 않습니다. 참조 여기에

답변:


296

메인 큐로 블록 디스패치는 일반적으로 백그라운드 큐에서 수행되어 일부 백그라운드 처리가 완료되었음을 알립니다.

- (void)doCalculation
{
    //you can use any string instead "com.mycompany.myqueue"
    dispatch_queue_t backgroundQueue = dispatch_queue_create("com.mycompany.myqueue", 0);

    dispatch_async(backgroundQueue, ^{
        int result = <some really long calculation that takes seconds to complete>;

        dispatch_async(dispatch_get_main_queue(), ^{
            [self updateMyUIWithResult:result];
        });    
    });
}

이 경우 백그라운드 큐에서 긴 계산을 수행하고 계산이 완료되면 UI를 업데이트해야합니다. UI 업데이트는 일반적으로 기본 대기열에서 수행해야하므로 두 번째 중첩 dispatch_async를 사용하여 기본 대기열로 '신호'합니다.

메인 큐로 다시 디스패치 할 수있는 다른 예가있을 수 있지만 일반적으로 이런 식으로 수행됩니다. 즉, 백그라운드 큐로 디스패치 된 블록에서 중첩됩니다.

  • 백그라운드 처리 완료-> UI 업데이트
  • 백그라운드 큐에서 처리 된 데이터 청크-> 다음 청크를 시작하도록 기본 큐 신호
  • 백그라운드 큐의 수신 네트워크 데이터-> 메시지가 도착했다는 메인 큐에 신호를 보냅니다.

왜 당신은 메인 큐 에서 메인 큐로 디스패치하고 싶을 까요 ... 글쎄, 일반적으로 다음 번 실행 루프를 위해 몇 가지 작업을 예약하기 위해 할 수는 없습니다.


아, 알겠습니다 그래서 맞습니다. 이미 기본 대기열에있는 경우 다른 대기열에 있고 UI를 업데이트하려는 경우에는 이점이 없습니다. 감사.
Duck

메인 대기열 에서이 작업을 수행하는 것이 왜 그렇게 유용하지 않은지에 대한 대답을 편집했습니다.
Robin Summerhill

또한 iOS 4에 버그가 있다고 생각합니다 (iOS 5에있을 수 있음). 주 스레드에서 기본 대기열로 dispatch_sync가 중단되는 원인이되므로 완전히 수행하지 않는 것이 좋습니다.
joerick

10
그것은 버그가 아니며, 예상되는 행동입니다. 그다지 유용한 동작은 아니지만 dispatch_sync를 사용할 때는 항상 교착 상태를 알고 있어야합니다. 시스템이 항상 프로그래머의 실수로부터 당신을 보호한다고 기대할 수는 없습니다.
Robin Summerhill

2
여기서 backgroundQueue는 무엇입니까? 어떻게 backgroundQueue 개체를 만들려면 어떻게해야합니까
Nilesh TUPE에게

16

메인 스레드에서 메인 큐로 블록을 전달하는 것이 유용 할 수 있습니다. 메인 큐는 큐에있는 다른 블록을 처리 할 수있는 기회를 제공하므로 다른 모든 것을 실행하지 못하게 막지 않습니다.

예를 들어 많은 동시 연결을 처리하는 본질적으로 단일 스레드 서버를 작성할 수 있습니다. 대기열의 개별 블록이 너무 오래 걸리지 않는 한 서버는 새로운 요청에 응답합니다.

만약 당신의 프로그램이 이벤트에 응답하는 데 평생을 보낸다면 이것은 자연 스러울 수 있습니다. 메인 큐에서 실행되도록 이벤트 핸들러를 설정 한 다음 dispatch_main ()을 호출하면 스레드 안전성에 대해 전혀 걱정할 필요가 없습니다.


11

dispatch_async와 dispatch_sync의 차이점에 대해 궁금한 점에서 귀하의 질문을 올바르게 이해하고 있습니까?

dispatch_async

블록을 비동기 적으로 대기열에 발송합니다. 의미하는 것은 블록을 큐에 보내고 메소드에서 나머지 코드의 실행을 계속하기 전에 블록이 돌아 오기를 기다리지 않는다는 의미입니다.

dispatch_sync

블록을 동 기적으로 대기열에 발송합니다. 이렇게하면 블록의 실행이 끝날 때까지 메소드에 남아있는 코드가 더 이상 실행되지 않습니다.

나는 주로 dispatch_async메인 큐에서 작업을 수행하고 장치가 가질 수있는 추가 코어를 활용하기 위해 백그라운드 큐를 사용했습니다 . 그런 다음 dispatch_asyncUI를 업데이트 해야하는 경우 기본 스레드로 이동하십시오.

행운을 빕니다


1
감사하지만 메인 대기열에있는 것을 메인 대기열로 보내는 것의 이점에 대해 묻고 있습니다.
Duck

9

유용한 작업 중 하나는 긴 작업 전에 스피너 설정과 같은 UI 활동에 유용합니다.

- (void) handleDoSomethingButton{

    [mySpinner startAnimating];

    (do something lengthy)
    [mySpinner stopAnimating];
}

긴 일 동안 메인 스레드를 차단하고 UIKit이 실제로 스피너를 시작하지 못하게하기 때문에 작동하지 않습니다.

- (void) handleDoSomethingButton{
     [mySpinner startAnimating];

     dispatch_async (dispatch_get_main_queue(), ^{
          (do something lengthy)
          [mySpinner stopAnimating];
    });
}

실행 루프로 제어를 반환하여 UI 업데이트를 예약하고 스피너를 시작한 다음 디스패치 큐에서 다음 항목을 가져옵니다. 실제 처리입니다. 처리가 완료되면 애니메이션 중지가 호출되고 실행 루프로 돌아가 UI가 중지로 업데이트됩니다.


@Jerceratops 예. 그러나 현재 runloop가 완료 될 수 있습니다.
Dan Rosenstark

3
예,하지만 여전히 끔찍합니다. 여전히 UI를 차단합니다. 이 바로 다음에 다른 버튼을 누를 수 있습니다. 또는 시도하고 스크롤하십시오. 메인 스레드에서 "(길이가 길다)"는 발생하지 않아야하며, 버튼 클릭 "종료"를 허용하는 dispatch_async는 적합한 솔루션이 아닙니다.
Jerceratops

8

스위프트 3, 4 및 5

메인 스레드에서 코드 실행

DispatchQueue.main.async {
    // Your code here
}

1

비동기는 비동기를 의미하므로 대부분을 사용해야합니다. 메인 스레드에서 동기화를 호출하면 작업이 완료 될 때까지 UI가 잠길 수 있습니다. Swift에서 더 좋은 방법은 다음과 같습니다.

runThisInMainThread { () -> Void in
    // Run your code like this:
    self.doStuff()
}

func runThisInMainThread(block: dispatch_block_t) {
    dispatch_async(dispatch_get_main_queue(), block)
}

내 저장소에 표준 기능으로 포함되어 있습니다. https://github.com/goktugyil/EZSwiftExtensions

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.