Serial - Concurrency / Async - Sync

Serial - Concurrency / Async - Sync

Serial - Concuurency 와 Async-Sync는 얼핏 보면 비슷한 작동원리 같다.

하지만 다르다. 하나씩 뜯어보자.

Async - Sync

Async 와 Sync는 작업 입장에서 요청과 응답의 관점이다.

응답 = return

  • 난 이 일이 요청 즉시 응답을 줬으면 좋겠어 -> Sync

  • 난 이 일이 요청은 하지만 응답은 천천히 줘도 돼 -> Async

Serial - Concurrency

Serial 과 Concurrency의 관계는 큐의 입장에서 일을 처리 하는 과정이다.

Serial

  • 일을 순차적으로 한다. (일의 끝을 보고 다음 일을 한다.)

Concurrency

  • 일을 동시 다발적으로 한다.

1번 코드 블럭

let concurrentQueue = DispatchQueue.init(label: "Concurrency", attributes: .concurrent)
concurrentQueue.sync  { print("start") } // 1️⃣번 작업
concurrentQueue.async { for _ in 0...5 { print("async") }} // 2️⃣번 작업
concurrentQueue.sync  { for _ in 0...5 { print("sync") } } // 3️⃣번 작업
concurrentQueue.sync  { print("end") } // 4️⃣번 작업

1번 코드 블럭은 Disaptchqueue가 concurrent로 작업한다.

  1. 1️⃣번 작업이 등록된다. sync로 등록 -> 바로 출력한다.

  2. 1️⃣번 작업이 끝난 후에 2️⃣번 작업이 등록된다. async로 등록

    • 출력을 시작한다. 하지만 concurrent 이므로 다음 작업으로 넘어간다.
  3. 3️⃣번 작업이 등록된다. sync로 등록 -> 바로 출력한다.

  4. But. 2️⃣작업이 이미 실행중이다. concurrent 하므로 2️⃣, 3️⃣ 동시에 작업된다.

  5. 하지만 2️⃣작업이 끝날 때 까지 4️⃣은 시작하지 않는다.

  6. 2️⃣작업이 끝난 후에 4️⃣작업이 시작된다.

2번 코드 블럭

let serialQueue = DispatchQueue.init(label: "Serial")
serialQueue.sync  { print("start") } // 1️⃣번 작업
serialQueue.async { for _ in 0...5 { print("async") }} // 2️⃣번 작업
serialQueue.sync  { for _ in 0...5 { print("sync") } } // 3️⃣번 작업
serialQueue.sync  { print("end") } // 4️⃣번 작업

비슷하지만 살짝 다르다. 1번은 Concurrency 하게 작동하고 2번은 Serial로 동작한다.
* DispatchQueue의 default는 Serial 하게 작동한다.

  1. 1️⃣번 작업이 sync로 등록된다.

  2. 1️⃣번 작업이 끝난 후에 2️⃣번 작업이 시작된다.

    • async로 등록되었지만 DispatchQueue가 Serial 하다. 즉 작업이 끝날 때 까지 다음 작업은 실행하지 않는다.
      * 작업이 실행하지 않는다 였다. 코드가 실행 안되는건 아니다.
  3. 3️⃣번 sync로 작업이 등록된다. 만약 2️⃣번 작업이 안 끝났다면 3️⃣번 작업은 기다린다.

  4. 3️⃣번 작업이 끝나면 4️⃣번 작업이 실행된다.

살짝 미묘하게 다름을 인지했음 좋겠다.

문제를 통해서 다시 한 번 살펴보자.


let concurrentQueue = DispatchQueue.init(label: "Concurrency", attributes: .concurrent)
concurrentQueue.sync  { print("start") } // 1️⃣번 작업
concurrentQueue.async { for _ in 0...5 { print("async") }} // 2️⃣번 작업
concurrentQueue.sync  { for _ in 0...5 { print("sync") } } // 3️⃣번 작업
print("💙")
concurrentQueue.sync  { print("end") } // 4️⃣번 작업

Quiz) 💙보다 sync가 먼저 출력 될 수 있을까? ❌

3️⃣번 작업이 등록 된 후 DispatchQueue가 concurrent 하더라도 3️⃣번 작업이 안비켜 주고 있는 것이다.

그러므로 3️⃣번 작업이 다 끝나야 💙가 출력될 수 있다.

Quiz) 💙보다 async가 늦게 될 수 있을까? ✅

2️⃣번 작업은 이미 등록이 되어 async하게 작업되고 있다. 그렇기에 💙출력과 관계 없이 작업이 진행된다. 그렇기에 async 출력이 늦을 수 있다.

let serialQueue = DispatchQueue.init(label: "Serial")
serialQueue.sync  { print("start") } // 1️⃣번 작업
serialQueue.async { for _ in 0...5 { print("async") }} // 2️⃣번 작업
serialQueue.sync  { for _ in 0...5 { print("sync") } } // 3️⃣번 작업
print("💙")
serialQueue.sync  { print("end") } // 4️⃣번 작업

Quiz) 💙보다 async가 늦게 될 수 있을까? ❌

  1. 2️⃣번 작업이 async로 등록되었다.

  2. DispatchQueue가 serial 하므로 3️⃣번 작업이 요청 되었다 하더라도 2️⃣이 끝나기 전까지 시작하지 못한다.

  3. 3️⃣번이 끝나지 않으면 💙도 출력될 수 없다

그러므로 💙보다 async가 늦게 될 수 없다.


참고 했던 페이지