Sendable

Groot·2022년 12월 21일
0

TIL

목록 보기
121/148
post-thumbnail

TIL

🌱 난 오늘 무엇을 공부했을까?

📌 Swift Concurrency - 3

📍 Sendable Types

  • Task나 Actor 인스턴스 내부에서 수정이 가능한 변수나 프로퍼티를 포함한 형태를 동시성 도메인이라 한다.
  • 일부 데이터들은 변경은 가능하지만, 중복 액세스로부터 보호되지 않기 때문에 동시성 도메인 간에 공유할 수 없다.
    • 여기에서 동시성 도메인에서 다른 동시성 도메인으로 안전하게 공유할 수 있는 유형을 Sendable Types 이라고 한다.

🔗 일반적으로 Sendable한 유형

  • 값 타입
    • 내부에 Sendable한 타입만 있다는 가정 하에
  • 변경이 불가능한 참조 타입
  • 내부상태에 대한 접근을 내부적으로 관리하는 참조 타입 <- Actor?
    • 읽기 전용 프로퍼티만 있는 클래스
    • @Sendable로 표시 된 함수나 클로저

📍 Sendable Structures and Enumerations

  • 구조체나 열거형도 내부에 Sendable한 타입만 있어야 Sendable 하다고 볼 수 있다.

  • 아래의 요구 사항을 충족하는 구조체 및 열거형은 암묵적으로 Sendable을 준수한다고 본다.

    • 상태가 변하지 않는 구조 및 열거형
    • pubic 하지않고, @usableFromInline라는 키워드가 없을 때
  • 만약 Sendable하지 않은 stored properties이 있는 구조체와 Sendable하지 않은 관련 값이 있는 열거형은 @unchecked Sendable 키워드로 표시한다.

    • 이렇게 하게되면 Sendable의 요구사항을 충족하는지 컴파일 타임에 검사를 하지 않는다. 개발자가 직접 확인해야함.

📍 Sendable Actors

  • Actor는 mutable state에 대한 모든 접근이 순차적으로 수행되기 때문에 모든 액터 유형은 암묵적으로 Sendable을 준수한다.

📍 Sendable Classes

  • Sendable 프로토콜 요구 사항을 충족하려면 클래스는 다음을 충족해야 한다.

    • final 표시로 상속을 막는다.
    • immutable하고 sendable한 저장 프로퍼티만 포함
    • superclass가 없거나 NSObject를 superclass로 사용
  • @MainActor로 표시된 클래스는 암시적으로 Sendable 하다.

    • main actor가 해당 상태에 대한 모든 액세스를 조정하기 때문에 클래스는 mutable and nonsendable한 저장 속성을 가질 수 있다.
  • 위의 요구 사항을 충족하지 않는 클래스는 @unchecked Sendable로 표시한다.

    • 구조체와 마찬가지로 Sendable의 요구사항을 충족하는지 컴파일 타임에 검사를 하지 않는다. 개발자가 직접 확인해야함.

📍 Sendable Functions and Closures

  • Sendable 프로토콜을 준수하는 대신 @Sendable 속성을 사용하여 sendable 함수 및 클로저를 표시
    • 함수 또는 클로저가 캡처하는 모든 값은 sendable해야한다.
    • sendable한 클로저는 값별 캡처만 사용해야 하며 캡처된 값은 sendable해야한다
  • 유형 주석으로 @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을 채택하도록 했다.

  • 처음엔 클래스와 구조체 둘 모두 아무런 프로퍼티도 넣어주지 않았지만, final 클래스가 이 아니기 때문에 Sendable 하지않으니 @unchecked Sendable 키워드를 사용하라고 나온다.

  • 클래스에 final을 넣어주면, 경고가 사라진다!


  • 이번엔 Int 타입변수를 넣어보자.
  • 구조체엔 값 타입 변수가 있어서 Sendable 하지만, 클래스에 들어간 값 타입 변수는 결국 참조 타입이기 때문에 Sendable 하지않다.


    변수를 상수로 변경해주니 경고는 사라졌다. 읽기 전용 타입이기 때문에 값이 수정될 일이 없어서 race condition 문제가 일어나지 않기 때문이다.


  • 이번엔 구조체에 Sendable 하지않은 클래스를 변수로 넣어줬더니 Sendable하지 않다고 경고가 나온다. 값타입 구조체 내부에 Sendable 하지않은 참조타입이 존재하기 때문이다.
  • 이번엔 클래스에 변수를 제거한 후 시도했지만, 여전히 Sendable 하지않다.

    현재 우리는 나는클래스는 Sendable 하다는 걸 알지만, 컴파일러가 보기엔 Sendable 하지않기 때문이다. 그러면 어떻게 할까?

  1. 나는클래스에 Sendable을 채택시켜 컴파일러에게 Sendable 하다고 알려줬더니 경고가 사라졌다.
  2. @unchecked Sendable 키워드를 사용해서 컴파일러가 확인하지 않도록 했다.

    2번의 방법을 사용하면 실제로 Sendable 한게 아니라 체크를 하지않도록만 하기 때문에 race condition 문제가 생길수도 있다고 생각된다.

📍 결론

  • 동시성 프로그래밍에서 Data Race 문제가 생기지 않는 Thread Safe한 타입은 Sendable하다라고 볼 수 있고 암시적으로 채택하고있다.
  • 기본적으로 Sendable한 Actor를 사용하는 방법이 간편하지만, Actor는 모든 메서드에 await을 붙여줘야 하기 때문에 비동기로 동작하지 않아도 되는 함수들도 비동기로 동작한다는 느낌을 준다???
  • 이런 불편함을 피하기 위해 우리가 직접 Sendable한 타입을 만들 수 있는데 그 방법은 Sendable 프로토콜을 따르고 제약사항을 지키는 것.
  • 함수나 클로저는 뭐라는지 모르겠다.
profile
I Am Groot

0개의 댓글