강의

멘토링

로드맵

Inflearn brand logo image

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

김도윤님의 프로필 이미지
김도윤

작성한 질문수

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

참고 코드 자료 7-StructuredConcurrency(102, 103줄) 오타?

해결된 질문

작성

·

14

0

자주하는 질문 모음

링크: https://pointed-earwig-996.notion.site/Swift-Concurrency-for-Swift-6-Part-1-22eecb0b83154ac28c7c66446f6e54e1?pvs=4

 

자주하는 질문을 먼저 확인 부탁드리며, 질문은 최대한 구체적으로하셔야 빠르게 답변드릴 수 있습니다.

 

[질문 예시]

(1) 몇강, 몇초의 내용이 잘 이해가 안갑니다. (제가 적어놓은 강의 번호 "10강, 7분 강의 내용 중에... " )

(2) 강의자료 몇페이지의 내용이 잘 이해가 안갑니다.

(3) 정확하게 어떤 포인트에 대한 내용이 이해가 안갑니다. 다시 설명해주실 수 있나요?

 

동시성 강의 코드파일 7번(7-StructuredConcurrency(102, 103줄) ) 내용인데요

전체코드

func fetchAsyncLetTwoImages() async throws -> (UIImage, UIImage) {
    let start = Date()
    /// 구조적 동시성 작업의 생성 (하위 작업의 생성)
    async let image1 = try await fetchImage(num: 1)
    async let image2 = try await fetchImage(num: 2)
    
    let images = try await (image1, image2)
    print(Date().timeIntervalSince(start).formatted(.number.precision(.fractionLength(1))))
    return images
}

이렇게 되어 있는데 async let image1 위치에서 fetchImage(num:1)의 값을 기다리는 형태입니다. 아마도 이렇게 바뀌는게 맞지 않나 싶습니다.

    /// 구조적 동시성 작업의 생성 (하위 작업의 생성)
    async let image1 = fetchImage(num: 1)
    async let image2 = fetchImage(num: 2)

그런데 위의 코드는 순서대로 결과값을 받는 경우이고 아래 코드는 동시에 돌려서 빨리 나오는 결과값이 먼저 반영되나 싶었는데 그것도 애매하네요.

A코드

    /// 구조적 동시성 작업의 생성 (하위 작업의 생성)
    async let image1 = try await fetchImage(num: 1)
    async let image2 = try await fetchImage(num: 2)

B코드

    /// 구조적 동시성 작업의 생성 (하위 작업의 생성)
    async let image1 = fetchImage(num: 1)
    async let image2 = fetchImage(num: 2)

실제로 두 코드를 돌려보니 A코드는 4.8 ~ 3.2초 걸렸는데 대략 평균적으로 3.6초 걸리고, B코드는 4.2 ~ 2.5초 걸려서 대략 평균적으로 3.3초 정도 걸리더라구요.
image1과 image2는 try await Task.sleep(for: .seconds(2))가 걸려 있어 각각 2초씩이어서 동시에 돌아가서 결과를 받으면 2초 조금 넘을 것 같고 순서대로 받으면 4초 조금 넘을 것입니다. 그런데 두 코드 모두 4초가 안걸리는 경우가 많았다는 점에서 동시성이 적용되는 것 같습니다. 그런데 어떤 속도의 차이가 있을까 했는데 별 차이가 없는 느낌이기도 합니다.
Claude에게 물어보니 A코드가 동시성의 효과를 보지 못한다고 하지만 속도 면에서 B코드가 특별히 빠르다고 단정하기도 애매해서요.
오타라고 생각되지만 A코드는 어떤 의미가 있을까 궁금합니다.

답변 3

0

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

아, 네 맞네요ㅠㅠ
오타가 있었네요!

 

네 A코드의 형태는 잘못되었고, (아래와 같은) 사용하신 B의 형태가 정확히 맞습니다.
(자료도 수정해 놓겠습니다.)

    /// 구조적 동시성 작업의 생성 (하위 작업의 생성)
    async let image1 = fetchImage(num: 1)
    async let image2 = fetchImage(num: 2)


질문에 정확한 답변을 드리고 싶지만..

제 생각에는 잘못된 코드를 분석한다는게 크게 의미가 없을 것 같습니다..ㅠㅠ 어차피 A코드와 같은 형태로 사용하는 것이 아니라, 잘못된 코드일뿐인 것이죠. (잘못된 코드인데, 자체적으로 컴파일러가 오류를 잡아주지 않는 것일뿐이라고 보시면 될 것 같습니다.)

 

그냥 단순히, 진짜 제 개인적인 뇌피셜로는 내부적으로 B코드와 완전히 동일하게 동작할 것 같긴합니다.

    /// 구조적 동시성 작업의 생성 (하위 작업의 생성)
    async let image1 = try await fetchImage(num: 1)
    async let image2 = try await fetchImage(num: 2)

왜냐면, 위와 같은 코드에서 컴파일 될때, 왼쪽의 코드인.. async let의 코드를 먼저 컴파일 시킬 것이기 때문에, 실제 async let image1 코드에서 일단 비동기 함수를 호출 시키고 다음 줄의 코드로 넘어가는 동작으로 async let image2를 컴파일 시킬 것 같습니다.

(다만, 측정하신 시간이 다르게 나온 이유는 정말 단순하게 플레이그라운드 실행 환경의 문제이지 않을까 싶습니다. 수백번의 실험을 해보면 얼추 비슷하게 나올 것 같습니다.)

 

코드 내용을 주의 깊게 봐주셔서 감사합니다. :)

김도윤님의 프로필 이미지
김도윤
질문자

친절한 설명 감사합니다.

0

김도윤님의 프로필 이미지
김도윤
질문자

A코드

func fetchAsyncLetTwoImages() async throws -> (UIImage, UIImage) {
    let start = Date()
    /// 구조적 동시성 작업의 생성 (하위 작업의 생성)
    async let image1 = try await fetchImage(num: 1)
    async let image2 = try await fetchImage(num: 2)
    
    let images = try await (image1, image2)
    print(Date().timeIntervalSince(start).formatted(.number.precision(.fractionLength(1))))
    return images
}

B코드
func fetchAsyncLetTwoImages() async throws -> (UIImage, UIImage) {
    let start = Date()
    /// 구조적 동시성 작업의 생성 (하위 작업의 생성)
    async let image1 = fetchImage(num: 1)
    async let image2 = fetchImage(num: 2)
    
    let images = try await (image1, image2)
    print(Date().timeIntervalSince(start).formatted(.number.precision(.fractionLength(1))))
    return images
}
앨런(Allen)님의 프로필 이미지
앨런(Allen)
지식공유자

네 오타입니다.ㅠ 위의 답변 참고 부탁드립니다. :)

0

안녕하세요, 인프런 AI 인턴입니다. 김도윤님께서 주신 질문을 잘 읽었습니다. 질문 내용은 Swift Concurrency에서의 async let 사용에 대한 의문과 성능 차이에 관련된 내용입니다.

A코드 vs B코드 차이

  1. A코드

    async let image1 = try await fetchImage(num: 1)
    async let image2 = try await fetchImage(num: 2)
    

    이 코드는 async let 을 사용하여 두 이미지 fetch 작업을 동시에 시작합니다. try awaitfetchImage 함수가 비동기 작업인 경우 에러를 던질 수 있음을 처리하기 위해 필요합니다.

  2. B코드

    async let image1 = fetchImage(num: 1)
    async let image2 = fetchImage(num: 2)
    

    이 코드는 비슷한 맥락이지만 try await 부분이 생략되어 있습니다. 이 경우 fetchImageawait가 필요 없는 함수라면, 사용이 가능합니다.

성능과 동시성

  • 두 코드 모두 async let을 사용함으로써 구조적 동시성을 가지며, 실제로는 두 이미지의 fetch가 동시에 시작됩니다.
  • fetchImage 함수 내부의 Task.sleep으로 인해, 동시적으로 실행될 때 약 2초 이후 첫 번째 이미지가 완료되고, 그다음 두 번째가 완료된다고 가정할 수 있습니다.
  • A코드와 B코드 모두 동시성을 사용하고 있고, 처리 시간이 크게 다르지 않다면, 이는 우연에 의한 가능성이 큽니다.

A코드의 의미

  • A코드의 try await는 오류가 발생할 수 있는 구문을 안전하게 실행하기 위해 사용됩니다.
  • 코드의 안정성과 에러 처리 관점에서 더 권장되는 방식입니다.

더 알아보기

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

김도윤님의 프로필 이미지
김도윤

작성한 질문수

질문하기