Sendable에 대해 알아봅시다

som·2024년 1월 2일
0

SwiftAnatomy

목록 보기
7/9

2024년 첫 포스팅을 Sendable로 하게 되었습니다~
(작년에 하려고 한 건데 이게 맞나)

이 글을 보시는 분들 2024년 한 해도 잘 보내시길 바랍니다 0.<~

개념

해당 코드는 swift > stdlib > public > core > Sendable.swift에서 볼 수 있습니다.

@_marker public protocol Sendable { }

복사를 통해 동시성 도메인 간에 값을 안전하게 전달할 수 있는 타입입니다.
한 동시성 도메인에서 다른 동시성 도메인으로 Sendable한 타입의 값을 안전하게 전달할 수 있습니다. 예를 들어 행위자의 메소드를 호출할 때 Sendable한 값을 인수로 전달할 수 있습니다. 다음은 모두 Sendable으로 표시될 수 있습니다.

  • 값 타입
  • 변경 가능한 저장소가 없는 참조 타입
  • 내부적으로 상태에 대한 액세스를 관리하는 참조 타입
  • 함수 및 클로저(@Sendable로 표시)

이 프로토콜에는 필수 메서드나 프로퍼티가 없지만 컴파일 타임에 적용되는 의미론적 요구 사항이 있습니다. 이러한 요구 사항은 아래 섹션에 나열되어 있습니다. Sendable에 대한 적합성은 해당 타입의 선언과 동일한 파일에서 선언되어야 합니다.

컴파일러 적용 없이 Sendable에 대한 적합성을 선언하려면 @unchecked Sendable을 작성하세요. 예를 들어 잠금 또는 대기열을 사용하여 해당 상태에 대한 모든 액세스를 보호함으로써 확인되지 않은 Sendable 타입의 정확성에 대한 책임이 있습니다. Sendable에 대한 확인되지 않은 적합성은 적합성이 동일한 파일에 있어야 한다는 규칙의 적용을 비활성화합니다.

즉, Sendable은 동시성 과정에서 안전하게 값을 전달하는 타입입니다. 따로 해당 프로토콜에 필수 메서드나 프로퍼티가 없지만 의미상 Sendable은 해당 타입의 선언과 동일한 파일에서 선언되어야 합니다. 어렵게 보이지만 별로 어려운 이야기는 아닙니다. Sendable을 적용할 타입과 같은 파일 안에서 채택이 되어야 한다는 통상적인 의미로 보입니다.

컴파일러 적용 없이 @unchecked Sendable을 선언하여 직접 Sendable한지 체크하는 방법도 있습니다. 어떤 값이 오는지 확실하게 알 때만 사용하는 것이 좋아보입니다.

Sendable Structures and Enumerations

Sendable 프로토콜의 요구 사항을 충족하려면 열거형 또는 구조체에 전송 가능한 멤버 및 관련 값만 있어야 합니다. 어떤 경우에는 요구 사항을 충족하는 구조체와 열거형이 암시적으로 Sendable을 준수합니다.

  • 고정된 구조 및 열거형
  • 구조체 및 열거형
    공개되지 않고 @usableFromInline으로 표시되지 않습니다.

그렇지 않으면 Sendable에 대한 적합성을 명시적으로 선언해야 합니다.

보낼 수 없는 저장된 프로퍼티와 보낼 수 없는 관련 값이 있는 열거형이 있는 구조체는 @unchecked Sendable로 표시되어 Sendable 프로토콜의 의미론적 요구 사항을 충족하는지 수동으로 확인한 후 컴파일 시간 정확성 검사를 비활성화할 수 있습니다.

Sendable 프로토콜의 요구 사항을 충족하려면 열거형 또는 구조에 전송 가능한 멤버 및 관련 값만 있어야 한다는 것을 보면, 참조가 있을 경우에는 Sendable을 채택할 수 없는 거 같습니다. 이러한 요구사항을 충족하면 암시적으로 Sendable을 준수한다고 합니다.

그래서 코린이 시절.. 제가 동시성 프로그래밍할 때 작업할 값타입에 Sendable을 준수하지 않아도 잘 동작했던 것이었군요...!

Sendable Actors

Actor는 변경 가능한 상태에 대한 모든 액세스가 순차적으로 수행되도록 보장하므로 모든 Actor 타입은 암시적으로 Sendable을 준수합니다.

Actor에 대해서는 잘 몰라서 그러려니 하고 넘어가는데... 다음 포스팅은 Actor에 대해서 한 번 다뤄봐야겠어요!

Sendable Classes

Sendable 프로토콜의 요구 사항을 충족하려면 클래스는 다음을 수행해야 합니다.

  • final으로 표시됨
  • 변경할 수 없고 전송할 수 있는 저장된 속성만 포함
  • 슈퍼클래스가 없거나 NSObject를 슈퍼클래스로 사용

@MainActor로 표시된 클래스는 기본 행위자가 해당 상태에 대한 모든 액세스를 조정하기 때문에 암시적으로 전송 가능합니다. 이러한 클래스에는 변경 가능하고 전송할 수 없는 속성이 저장되어 있을 수 있습니다.

위의 요구 사항을 충족하지 않는 클래스는 @unchecked Sendable로 표시되어 Sendable 프로토콜의 의미론적 요구 사항을 충족하는지 수동으로 확인한 후 컴파일 시간 정확성 검사를 비활성화할 수 있습니다.

참조타입인 클래스는 수정에 대한 가능성을 컴파일러가 알 수 없기 때문에 저러한 제약이 생긴 거 같습니다.

Sendable Functions and Closures

Sendable 프로토콜을 따르는 대신 @Sendable 프로퍼티를 사용하여 전송 가능한 함수와 클로저를 표시합니다. 함수나 클로저가 캡처하는 모든 값은 전송 가능해야 합니다. 또한 전송 가능한 클로저는 값별 캡처만 사용해야 하며 캡처된 값은 전송 가능한 타입이어야 합니다.

전송 가능한 클로저를 기대하는 컨텍스트에서 요구 사항을 충족하는 클로저는 묵시적으로 Sendable을 준수합니다(예: Task.detached(priority:Operation:) 호출에서).

@Sendable을 타입 주석의 일부로 작성하거나 클로저 매개변수 앞에 @Sendable을 작성하여 클로저를 전송 가능으로 명시적으로 표시할 수 있습니다. 예를 들면 다음과 같습니다.

let sendableClosure = { @Sendable (number: Int) -> String in
    if number > 12 {
        return "More than a dozen."
    } else {
        return "Less than a dozen"
    }
}

오... 클로저나 메서드도 Sendable을 적용할 수 있군요! 어트리뷰트로 적용을 할 수 있는 것처럼 보입니다! 연산을 통해서 해당 값을 동시성 프로그래밍에 적용을 할 때 사용하면 요긴할 거 같습니다 ㅎㅎ

Sendable Tuples

Sendable 프로토콜의 요구 사항을 충족하려면 튜플의 모든 요소가 전송 가능해야 합니다. 요구 사항을 충족하는 튜플은 암시적으로 Sendable을 따릅니다.

Sendable Metatypes

Int.Type과 같은 메타타입은 암시적으로 Sendable 프로토콜을 따릅니다.

튜플과 메타타입도 암시적으로 Sendable 프로토콜을 준수한다고 합니다!

간단정리

Sendable은 복사를 통해 동시성 프로그래밍에서 안전하게 값을 보내주는 타입이기 때문에, 값의 안정성을 보장해줄 수 있는 타입입니다.

따란~ 이미 암시적으로 준수하고 있는 부분들이 많아서 따로 오류가 뜨지 않기 때문에 많이 쓰지는 않은 문법이었는데, 명시적으로 이 타입은 안전하다!를 표현해주는 방식으로도 활용해보면 좋을 거 같습니다~

profile
얼레벌레 취준 공부 중인 초보 개발자

0개의 댓글