DispatchQueue.main.async와 DispatchQueue.main.sync의 차이점


108

DispatchQueue.main.asyncUI 관련 작업을 수행하기 위해 오랫동안 사용 하고 있습니다.



스위프트 모두를 제공 DispatchQueue.main.async하고 DispatchQueue.main.sync, 두 메인 큐에 수행된다.



누구든지 그들 사이의 차이점을 말할 수 있습니까? 언제 각각을 사용해야합니까?



DispatchQueue.main.async {
    self.imageView.image = imageView
    self.lbltitle.text = ""

}

DispatchQueue.main.sync {
    self.imageView.image = imageView
    self.lbltitle.text = ""
}

답변:


54

당신이 사용하는 경우 async가 파견 블록이 실행될 때까지 기다리지 않고에서 호출 큐 이동을 할 수 있습니다. 반대로 sync호출 대기열을 중지하고 블록에서 보낸 작업이 완료 될 때까지 기다립니다. 따라서 sync교착 상태가 발생할 수 있습니다. DispatchQueue.main.sync메인 큐에서 실행 을 시도 하면 호출 큐가 디스패치 된 블록이 끝날 때까지 대기하지만 시작할 수도 없기 때문에 앱이 멈 춥니 다 (큐가 중지되고 대기 중이기 때문).

언제 사용 sync합니까? 다른 대기열에서 수행 된 작업을 기다린 다음 현재 대기열에서 계속 작업해야하는 경우

동기화 사용 예 :

직렬 대기열 sync에서는 하나의 스레드 만 보호 된 코드를 동시에 수행 할 수 있도록 뮤텍스로 사용할 수 있습니다 .


DispatchQueue.main.sync백그라운드 스레드에서 호출하는 것이 잘못 입니까?
Honey

@Honey 일반적으로 아니요, 그러한 호출에는 문제가 없지만 (메인 대기열이 무겁고 시간이 많이 걸리는 작업을 수행하지 않는 한) 실제로 이것이 필요한 상황을 생각할 수 없습니다. 확실히 더 나은 솔루션이 있어야합니다
안드레이 Chernukha

1
@Honey One 이러한 상황은 다음 문서에 설명 된대로 PhotoKit API에서 PHAssets의 CollectionView를 업데이트하는 것입니다. developer.apple.com/documentation/photokit/…
teacup

1
@teacup 흥미 롭습니다. 우리가 async거기에 전화하면 어떻게 달라지는 지 궁금합니다 . 나중에 스레드에 다른 것이 없기 때문에 차이를 만들지 않습니다. 그렇다면 그것은 DispatchQueue.main.sync {block1}; DispatchQueue.main.sync {block2};의미가 있었을 것입니다. 그러나 다른 블록이 없으면 DispatchQueue.main.sync {Oneblock}over 사용의 이점을 생각할 수 없습니다 DispatchQueue.main.async {Oneblock}. 둘 다 mainQueue 우선 순위 / 즉시 성을 갖게되며 아무것도 방해하지 않습니다.
Honey

3
@Honey "나중에 스레드에 다른 것이 없기 때문에"는 앱과의 모든 사용자 상호 작용을 처리하는 메인 스레드에있을 때 사실이 아닙니다. 예를 들어, 사용자는 photoLibraryDidChange가 업데이트 된 데이터 소스와 함께 반환되기 전에 다른 사진을 삭제하여 치명적인 불일치 오류를 일으킬 수 있습니다.
찻잔

166

왜 동시성인가?

데이터로드와 같은 무거운 작업을 앱에 추가하자마자 UI 작업 속도가 느려지거나 심지어 멈 춥니 다. 동시성을 사용하면 2 개 이상의 작업을 "동시에"수행 할 수 있습니다. 이 접근법의 단점은 스레드 안전성이 항상 제어하기 쉽지는 않다는 것입니다. Fe는 다른 스레드에서 동일한 변수를 변경하거나 다른 스레드에 의해 이미 차단 된 리소스에 액세스하는 것과 같이 다른 작업이 동일한 리소스에 액세스하려고 할 때입니다.

우리가 알아야 할 몇 가지 추상화가 있습니다.

  • 대기열.
  • 동기 / 비동기 작업 성능.
  • 우선 순위.
  • 일반적인 문제.

대기열

연속적 이거나 동시 적 이어야 합니다 . 동시에 글로벌 또는 비공개 .

직렬 대기열을 사용하면 작업이 하나씩 완료되고 동시 대기열로 작업이 동시에 수행되며 예기치 않은 일정에 따라 완료됩니다. 동일한 작업 그룹은 동시 대기열에 비해 직렬 대기열에서 더 많은 시간이 걸립니다.

고유 한 개인 대기열 ( 직렬 또는 동시 )을 만들거나 이미 사용 가능한 전역 (시스템) 대기열을 사용할 수 있습니다 . 주요 큐가 유일하다 시리얼 큐 의 모든 중 글로벌 큐 .

기본 대기열 (네트워크에서 데이터를로드하는 경우)에서 UI 작업을 참조하지 않는 무거운 작업을 수행 하지 말고 다른 대기열에서 수행하여 UI가 고정되지 않고 사용자 작업에 응답하도록하는 것이 좋습니다. 다른 대기열에서 UI를 변경하면 예상치 못한 다른 일정과 속도로 변경 될 수 있습니다. 일부 UI 요소는 필요하기 전이나 후에 그릴 수 있습니다. UI가 충돌 할 수 있습니다. 또한 전역 대기열시스템 대기열 이므로 시스템에서 실행할 수있는 다른 작업이 있음을 명심해야 합니다.

서비스 품질 / 우선 순위

큐는 다른이 의 QoS (서비스 품질) 작업을 수행 설정 우선 순위를 (여기에 가장 낮은에 가장 높은에서) :
.userInteractive - 주요 큐가
.userInitiated을 - 사용자가 시작한 작업하는 몇 가지 응답에 대한 사용자 대기
.utility - 작업에 대한 이는 약간의 시간이 소요 및 데이터 작업 등 즉각적인 대응을 필요로하지 않습니다
.background를 ) 시각적 인 부분과 관련되고 있지 않은 작업 완료 시간에 대한 엄격한하지 않습니다 -. qos 정보를 전송하지 않는 .default

도 있습니다 . 검출 할 수 없었다 경우 QoS를

qos.userInitiated.utility 사이에 사용됩니다 .

작업은 동기식 또는 비동기식 으로 수행 할 수 있습니다 .

  • 동기 함수는 작업이 완료된 후에 만 ​​현재 대기열로 제어를 반환합니다. 큐를 차단하고 작업이 완료 될 때까지 기다립니다.

  • 비동기 함수는 다른 대기열에서 수행되도록 작업이 전송 된 직후 현재 대기열로 제어를 반환합니다. 작업이 완료 될 때까지 기다리지 않습니다. 대기열을 차단하지 않습니다.

일반적인 문제.

프로그래머가 동시 앱을 프로젝션하는 동안 범하는 가장 일반적인 실수는 다음과 같습니다.

  • 경쟁 조건 -앱이 작동 할 때 발생하는 코드 부분 실행 순서에 따라 다릅니다.
  • 우선 순위 반전 -일부 리소스가 차단되어 우선 순위가 높은 작업이 더 작은 우선 순위 작업이 완료되기를 기다리는 경우
  • 교착 상태 -일부 대기열이 이러한 대기열 중 일부에 의해 이미 차단 된 소스 (변수, 데이터 등)를 무한히 기다릴 때.

메인 대기열에서 동기화 기능을 호출하지 마십시오 .
메인 대기열에서 동기화 기능을 호출하면 대기열이 차단되고 대기열이 작업이 완료되기를 기다리고 있지만 대기열이 시작되지 않아 작업을 완료 할 수 없습니다. 이미 차단되었습니다. 교착 상태 라고 합니다.

동기화는 언제 사용합니까? 작업이 끝날 때까지 기다려야 할 때. 일부 함수 / 메서드가 이중 호출되지 않았는지 확인할 때 Fe. Fe 우리는 동기화가 있으며 완전히 완료 될 때까지 이중 호출을 방지하려고합니다. 이 문제에 대한 몇 가지 코드는 다음과 같습니다
. IOS 장치에서 오류 충돌 보고서의 원인을 찾는 방법은 무엇입니까?


3
"주 대기열에서 동기화 기능을 절대 호출하지 마십시오"가 옳다고 생각하지 않습니다. 예를 들어 각 개체를 사용하고 늘리는 데 필요한 전역 카운터가있는 경우와 같이 주 스레드에서 sync를 호출하는 경우가 있습니다. dispatchQueue.sync {count + = 1; self.orderId = count}
Elisha Sterngold 2011

6
QOS 클래스-.userInteractive는 기본 대기열이 아닙니다.
Kunal Shah

1
DispatchQueue.main.sync백그라운드 스레드에서 호출하는 것이 잘못 입니까?
Honey

1
@Honey, 아니, 그렇게 부르는 것이 잘못은 아니지만 내 경험에 따르면 sync가 아닌 DispatchQueue.main.async를 더 많이 호출 할 것입니다.
James Kim

2
현재 큐에서 sync () 함수를 호출해서는 안된다고 말하는 것이 더 정확하지 않을까요? 내가 올바르게 이해한다면 다른 대기열에 있으면 메인 대기열에서 sync ()를 호출하는 것이 잘못이 아닙니다.
ykay

1

GCD작업 synchronously또는 [정보] 를 실행할 수 있습니다 asynchronously.

synchronous(블록 및 대기) 함수는 작업이 완료 될 때 컨트롤을 반환합니다.

asynchronous(디스패치 및 진행) 함수는 컨트롤을 즉시 반환하여 작업을 적절한 대기열로 보내지 만 완료 될 때까지 기다리지 않습니다.

[DispatchQueue]


0

sync또는 async메서드는 호출되는 큐에 영향을주지 않습니다.

sync스레드 차단 로부터 이 큐라고하지 않는 가 호출되어있다. 작업 실행을 기다릴 DispatchQueue것인지 DispatchQueue(직렬 대기열) 현재 작업이 완료되기 전에 다음 작업을 실행할 수 있는지 (동시 대기열) 를 결정 하는 속성입니다 .

따라서 DispatchQueue.main.async비동기 호출 인 경우에도 무거운 작업이 추가되면 해당 작업이 주 스레드에서 직렬로 실행되므로 UI가 고정 될 수 있습니다. 이 메서드가 백그라운드 스레드에서 호출되면 UI가 고정 된 것처럼 보이더라도 제어가 즉시 해당 스레드로 돌아갑니다. async전화가 걸렸기 때문 입니다.DispatchQueue.main

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