메인 스레드에서 작업을 수행하는 GCD


254

어떤 스레드에서나 콜백이 있습니다. 이 콜백을 받으면 메인 스레드에서 특정 작업을 수행하고 싶습니다.

이미 메인 스레드에 있는지 확인해야합니까, 아니면 아래 코드를 호출하기 전에이 확인을 수행하지 않으면 페널티가 있습니까?

dispatch_async(dispatch_get_main_queue(), ^{
   // do work here
});

116
5 년이 지난 후에도 여전히 GCD 블록의 구문을 기억하지 못하고 매번 여기서 끝납니다.
SpaceTrucker

7
@SpaceTrucker-그게 내가이 페이지에있는 동일한 이유입니다 : D
Matthew Cawley

4
9 년 후에도 여전히이 페이지에서 구문을 복사합니다.
오사

답변:


152

아니요, 이미 메인 스레드에 있는지 여부를 확인할 필요가 없습니다. 블록을 메인 큐에 디스패치하면 블록이 메인 스레드에서 직렬로 실행되도록 예약하는 것입니다. 해당 실행 루프가 실행될 때 발생합니다.

메인 스레드에 이미있는 경우 동작은 동일합니다. 블록이 예약되고 메인 스레드의 실행 루프가 실행될 때 실행됩니다.


3
질문은 "이 검사를 수행하지 않음으로써 페널티가 있는지"입니다. 비동기 디스패치가 불필요 할 때 성능 저하가 있다고 생각합니까, 아니면 사소한가요?
Dan Rosenstark

1
@Yar 대부분의 경우 눈에 띄는 성능 영향이 없다고 생각합니다. GCD는 경량 라이브러리입니다. 즉, 나는 다음과 같은 질문을 이해했다 : '아래 코드를 받았는데, 메인 스레드에 있는지 여부를 확인해야합니까?'

7
그러나 dispatch_sync를 사용하는지 확인해야합니다. 그렇지 않으면 교착 상태가 발생합니다.
Victor Engel

메인 대기열에 있고 메인 대기열로 async다시 발송 하면 대기열이 실행되지만 예상되는 작업 타이밍을 망칠 수 있습니다 . 이러한에서 UI 코드로 viewDidLoad() 될 때까지 실행되지 뷰가 먼저 표시됩니다 .
pkamb

106

위에서 설명한 비동기 디스패치 사례의 경우 메인 스레드에 있는지 확인할 필요가 없습니다. Bavarious에서 알 수 있듯이 이것은 메인 스레드에서 실행되도록 대기합니다.

그러나 a를 사용하여 위의 작업을 시도하고 dispatch_sync()콜백이 기본 스레드에 있으면 해당 시점에서 애플리케이션이 교착 상태가됩니다. 이 동작은 코드를 이동할 때 놀랐 기 때문에 여기 에 내 대답에 이것을 설명합니다 -performSelectorOnMainThread:. 내가 언급했듯이 도우미 함수를 만들었습니다.

void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

현재 사용중인 메소드가 현재 메인 스레드에없는 경우 메인 스레드에서 동기식으로 블록을 실행하고 블록이 있으면 인라인으로 실행합니다. 다음과 같은 구문을 사용하여이를 사용할 수 있습니다.

runOnMainQueueWithoutDeadlocking(^{
    //Do stuff
});

1
"runOnMainQueueSync"와 같이 호출하지 않겠습니까? 교착 상태가 될 수 있고 그렇지 않다는 사실은 내 코드 전체에서 갖고 싶지 않은 것입니다. 항상 감사합니다.
Dan Rosenstark

2
@Yar-나는이 도우미 함수를 사용하는 대신 메인 큐에서 블록을 동기식으로 발사하지 않는 이유를 분명히 알기 위해 그 이름을 썼습니다. 그것은 나 자신에게 생각 나게했다.
Brad Larson

3
이 기능으로 교착 상태가 여전히 가능합니다. 메인 큐 동기화> 다른 큐 동기화> 메인 큐는 교착 상태가됩니다.
hfossli

2
@hfossli-사실, 모든 경우를 처리하지는 않습니다. 내 사용법에서 항상 백그라운드 직렬 큐의 비동기 디스패치 또는 기본 스레드의 인라인 코드에서 호출했습니다. dispatch_set_specific()설명에 도움 이 될지 궁금합니다 . stackoverflow.com/a/12806754/19679 .
Brad Larson

1
[NSThread isMainThread]는 종종 YES를 반환하며 GCD 프로그래밍에서이 경우를 확인하기에 안전한 것으로 간주되지 않습니다. stackoverflow.com/questions/14716334/…
Will Larche

57

다른 답변에서 언급했듯이 기본 스레드의 dispatch_async가 좋습니다.

그러나 유스 케이스에 따라 단점을 고려할 수있는 부작용이 있습니다. 블록이 큐에서 스케줄되므로 제어가 실행 루프로 돌아갈 때까지 실행되지 않으므로 지연 효과가 있습니다. 블록의 실행.

예를 들어

NSLog(@"before dispatch async");
dispatch_async(dispatch_get_main_queue(), ^{
    NSLog(@"inside dispatch async block main thread from main thread");
});
NSLog(@"after dispatch async");

인쇄합니다 :

before dispatch async
after dispatch async
inside dispatch async block main thread from main thread

따라서 외부 NSLog 사이에서 블록이 실행될 것으로 예상하면 dispatch_async가 도움이되지 않습니다.


이것이 중요하다고 말할 필요가있다
Marc-Alexandre Bérubé

확인하고 싶기 때문에 코드가 메인 스레드에서 실행되거나 실행되지 않을 수 있습니다. 메인 스레드에서 이미 그 순서대로 실행됩니다. 그렇지 않으면 보장 할 수 없습니다. 따라서 다중 스레드 프로그래밍을 참조 할 때 특정 순서로 실행되도록 코드를 설계 하지 않아야합니다 . 비동기 콜백 방식을 사용하십시오.
ooops

1

메인 스레드에 있는지 확인할 필요가 없습니다. Swift에서이를 수행하는 방법은 다음과 같습니다.

runThisInMainThread { () -> Void in
    runThisInMainThread { () -> Void in
        // No problem
    }
}

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.