인프런 커뮤니티 질문&답변

ekth020216님의 프로필 이미지
ekth020216

작성한 질문수

앨런 Swift Concurrency for Swift 6 (Part-1)

async/await 키워드 설명 (큰그림 먼저 이해) (6강)

Task.sleep Non-blocking 추가 질문

작성

·

86

0

6강 14분48초에 Task.sleep이 논 블락킹 방식으로 진행되면서 해당 쓰레드에서 다른일을 처리할 수 있다고 하셨는데, sleep을 처리하는 동안 다른 일을 할 수 있는 예제 코드를 알수 있을까요? 

 

해당 강의 예제 코드에서는 sleep이 끝난 뒤에 코드가 실행되는 예시를 보여주셔서 어떻게 task.sleep 사이의 시간을 활용할 수 있는지 궁금합니다. 

답변 2

0

앨런(Allen)님의 프로필 이미지
앨런(Allen)
지식공유자

안녕하세요. ekth020216 님.

약간 내용을 다른 관점에서 잘 못 생각하신 것 같은데, 쓰레드가 비어있는 동안 다른 일처리를 우리가 직접적으로 시키는 것은 불가능해요.

 

예를 들어 2번 쓰레드에서 try await Task.sleep(for: .seconds(5)) 함수를 통해 5초동안 쓰레드를 양보한다고 말씀드렸는데, 해당 2번 쓰레드는 비어있는 동안 시스템(운영체제)이 알아서 비어있는 동안의 쓰레드를 사용한다는 의미이기 때문에.. 직접적으로 비어있는 동안 어떤 일처리를 시키겠다?는 이런식의 예제는 당연히 불가능합니다.

쓰레드를 양보해서, 운영체제에게 맡겼으니.. (다른 처리해야할 작업들이 있다면) 운영체제가 알아서 처리한다는 게 핵심이예요.

 

그래서 큰 의미는 없지만, 예시로 한번 말씀드려보면,

func performAsyncWork() async {
    print("작업 시작")
    
    Task {  // 작업 생성
        try await Task.sleep(for: .seconds(5)) // 5초 sleep
        print("Sleep 작업 완료 후 실행됨")
    }

    for i in 1...100000 {
        Task {   // 또다른 작업 100,000개 생성 ⭐️
             print("비동기 작업 중: \(i)")
        }
    }
    
    print("작업 종료")
}

Task {
    await performAsyncWork()
}

이런 코드가 있다고 치면, performAsyncWork라는 비동기 함수를 실행하면, 이 비동기 함수 안에서 작업을 생성하고 (제가 “작업 생성”이라고 주석해 놓은 부분) 5초동안 멈췄다가 그 다음 중 코드인 “Sleep 작업 완료 후 실행됨”을 출력할꺼예요.

 

그런데 작업(Task)을 생성하는 하단에 보시면, 반복문이 있는데, 반복문 내부에서 10만번의 비동기 작업을 또 생성하면서 출력을 합니다. (반복문 안에서 비동기 작업을 생성한다는 것은.. 뒤에 강의에서도 자세하게 또 말씀드리지만, 병렬적인 작업의 생성이죠.)

 

따라서 Task.sleep은 Non-blocking방식으로 실행된다고 말씀드렸는데, 예를 들어 만약에 2번 쓰레드 였다고 가정하면, (5초동안) 2번쓰레드를 양보한 동안에.. (2번 쓰레드는 지금 당장 할 일이 없으니) 아래 있는 반복문의 10만개의 여러 작업이니.. 반복문의 코드들이 2번 쓰레드를 사용할 수 있다는 것이죠.

 

결국, 이 Task(비동기 작업)를 생성하고 그 내부에서 동작하는 Non-blocking 방식은.. GCD와 마찬가지로 우리가 직접적으로 쓰레드를 사용하는 방식이 아니고, 추상화 되어 있어서.. 우리는 내부적으로 한차원 높은 관점에서 비동기적인 일처리를 Task로 보내면, Task내부에서 알아서 쓰레드를 양보하기도 하고, 사용하기도 하면서 운영체제와 알아서 소통하면서 처리해준다는 것이예요.

 

잘 생각해보시고, 이해가 안되시면 다시 질문 주세요 !

 

고맙습니다. :)

0

안녕하세요, 인프런 AI 인턴입니다. ekth020216님.

Task.sleep이 논 블락킹 방식으로 동작한다는 것은 해당 작업이 sleep 상태일 때 쓰레드 자원이 다른 작업에 사용될 수 있다는 의미입니다. 이 개념을 이해하기 위해서는 Swift의 동시성 모델에서의 비동기 작업의 특성을 이해해야 합니다.

아래는 Task.sleep을 비동기적으로 활용하는 예제 코드입니다. 이 코드에서는 sleep 동안 다른 비동기 작업을 수행합니다:

import Foundation

func performAsyncWork() async {
    print("작업 시작")
    
    _ = Task {
        try await Task.sleep(nanoseconds: 3 * 1_000_000_000) // 3초 sleep
        print("Sleep 작업 완료 후 실행됨")
    }

    for i in 1...5 {
        print("비동기 작업 중: \(i)")
        await Task.yield() // 다른 작업을 할 수 있도록 양보
    }
    
    print("작업 종료")
}

Task {
    await performAsyncWork()
}

위 예제에서 Task.sleep은 3초간 잠들어 있지만, sleep이 비동기적으로 동작하기 때문에 그동안 for 루프 안의 다른 비동기 작업이 계속 실행됩니다. Task.yield()는 현재 task를 잠시 멈추고 다른 task가 실행될 수 있도록 도와주는 역할을 합니다. 이 방식을 통해 sleep 중에도 다른 로직이 진행될 수 있습니다.

관련된 내용을 더 깊이 있게 이해하고 싶으시다면, 동시성과 비동기 프로그래밍의 기초와 Task 개념에 관한 추가 학습을 추천드립니다.

관련 유사한 질문을 고민하신 분들이 있었으며, 아래 링크를 통해 확인해 보실 수 있습니다:
- Dispatch Group 개념 중 “wait 을 통한 동기적인 기다림”에 대한 질문입니다. - 비동기 동작을 이해하는 데 도움이 되는 논의가 포함되어 있습니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

ekth020216님의 프로필 이미지
ekth020216

작성한 질문수

질문하기