해결된 질문
작성
·
72
0
안녕하세요, 강의를 들으면서 생긴 질문 세가지가 있습니다. 답변해주시면 너무 감사드리겠습니다.
Swift Concurrency에서 NSLock을 사용해도 되나요? 이전 GCD환경에서 데이터 동기화를 위해 사용하던 NSLock을 Swift Concurrency환경에서 사용해도 같은 효과를 볼수있을지 궁금합니다.
Actor에 접근할때는 await으로 Task를 따서 비동기적으로 접근하는데, 기존에 비슷한 참조타입인 class에 접근하는것보다 속도가 느려지는 이슈는 없을까요?
cpu에서 context switch를 하면, 저장하고 로딩하는 동기화하는 작업때문에 컨텍스트 스위칭이 비효율적이다 라고 설명해주셨는데,
그럼 swift concurrency에서는 task가 다른 cpu(다른 쓰레드) 에서 재개되는것도 동기화작업이 필요할텐데 이 작업은 비싼(?) 비효율적인 작업이 아닌가요?
질문이 조금 많은데.. 액터까지 강의 들으면서 궁금했던 점이라 부탁드립니다.
답변 3
1
1
네 안녕하세요 얌얌 님.
1)결국에, GCD이든 Swift Concurrency이든 동시성 프로그래밍에서 가장 문제인 것은 Thread-safe한 코드를 만드는 것이겠죠. (여러 쓰레드를 사용하면서, (메모리에 올라가있는) 데이터에 여러쓰레드(CPU)에서 동시에 접근하면.. 그건 본질적으로 그 데이터의 안정성을 보장할 수 없으니까요.) 물론 Swift Concurrency에서 NSLock을 사용하시는 것은 (그 자체로는) 전혀 문제는 없습니다. NSLock도 1개의 쓰레드에서의 접근을 보장하기 위해서 사용하는 것이니까요. 다만, 그럼 왜 Swift Concurrency를 사용하는 것이 좋을까요? 컴파일 시점부터 Thread-safety를 보장하기 위한 것입니다. 코드를 짤 때부터 안정성을 보장해주니.. (우리가 미쳐 발견하지 못한 오류를 컴파일러가 알아서 찾아주니) 실수할 염려가 없겠죠. NSLock로 구현하셔도 되지만, NSLock자체를 이용해서 잘못 구현했을 때의 오류는 컴파일러가 잡아주지 않습니다. 그러니.. NSLock의 사용은 우리가 개발자로서 실수를 하지 않았음을 "우리가 보장"하게 만들어야만 합니다. 그래서, 그 모든 개발자의 실수가 없다는 것(Thread-safe한 안전한 코드라는 것)을 언어차원에서 보장하겠다는 목적을 가지고 도입된 것이 Swift Concurrency 입니다.
2) 음.. 어떤 개념에서 속도가 느려질 수 있는지의 여부를 생각하게 되신 것인지는.. 제가 잘 모르겠습니다. 원칙적으로 class도 여러쓰레드(CPU)에서 접근하는 데이터라면, (직렬 GCD 같은) 직렬큐로 1개의 쓰레드에서만 안전하게 접근하도록 (또는 NSLock을 사용하거나, Semaphore를 사용해서) 만들어 줘야 합니다. (결국 Actor가 아니더라도 1개의 쓰레드에서만 접근해서 차례 차례 실행되어야 하는 것은 마찬가지인 것이죠.) 따라서 안전한 데이터를 보장하는 Actor로 구현한 자체가 느려질 수 있다고 생각하시는 부분은.. 잘못된 접근 법이 아닐까 생각합니다. (물론 저는 이론적인 측면에서 말씀드린 것이고, Swift Concurrency코드 자체의 내부적인 구현에 의해 오버헤드는 있을 수도 있지만, 그게 우리가 개발자로서 알고 써야하는 유의미한 부분은 아닐 것이라고 생각합니다. 그런 내용에 대한 어떠한 언급도 공식문서나 WWDC에서 말해주는 부분이 아니니까요.)
3) 본 강의의 첫번째 질문의 (제목: "재개될 때 스레드 변경시 왜 컨텍스트 스위칭이 발생하지 않는 건가요?") 이 질문 답변도 꼭 같이 확인해보시면 좋을 것 같습니다. 1개의 동일한 CPU를 사용하면서, 사용하던 쓰레드 객체를.. 운영체제에 반납하고, 다시 새로운 쓰레드 객체를 생성해서 사용하는 것은 스택 메모리를 교체하는 등도 필요하고.. CPU의 레지스터 상태를 교체하는 것도 필요하지만, 해당 동일한 1개의 CPU를 가지고 여러쓰레드를 사용하는 것보다는 그냥 아예 다른 CPU로 갈아타는 것이 비효율적이지는 않습니다. 실생활의 예시를 들어 쉽게 비유로 말씀드리면.. (1) 컨텍스트 스위칭: 후라이드 치킨을 먹다가, 똑같은 접시를 비우고 (씻고) 다시 양념치킨을 얻어서 먹다가.. (다시 접시를 비우고 씻고) 다시 후라이드 치킨을 먹는 것보다.. (2) CPU전환: 후라이드치킨 먹다가 (그릇 비우고 씻지 말고) 그냥 새로운 그릇에다가 양념치킨 먹는게 더 빠르다고 생각하시면 될 것 같습니다.
감사합니다. 🙂 또 궁금하신 것 있으시면 질문주세요!
0
안녕하세요, 인프런 AI 인턴입니다. 얌얌님께서 Swift Concurrency와 관련하여 세 가지 질문을 주셨네요. 각각의 질문에 대해 자세히 답변해 드리겠습니다.
NSLock은 Swift Concurrency 이전의 GCD 환경에서 종종 사용되던 동기화 방법입니다. Swift Concurrency는 보다 구조화된 방식으로 동시성 문제를 해결하고자 하므로, NSLock 대신 Actor를 사용하는 것이 더 자연스럽습니다. Actor는 동시성 모델 자체에 의해 보호되기 때문에, 별도의 락이 없어도 안전하게 사용할 수 있습니다. 따라서, Swift Concurrency 환경에서는 NSLock보다 Actor의 사용을 권장드립니다. 관련 질문 링크
Actor는 데이터 경쟁 상태를 방지하기 위해 고안된 구조이므로, 안전성을 더하는 대신 약간의 성능 저하가 발생할 수 있습니다. 실제로 Actor 내부의 메소드나 속성에 접근할 때 await을 사용하는데, 이는 비동기 작업으로 간주되어 추가적인 오버헤드가 발생할 수 있습니다. 그러나 일반적인 코드에서는 큰 영향을 미치지 않으며, 데이터의 안전성이 확보되기 때문에 장점이 큽니다. 앱의 성능에 민감한 부분에서는 상황에 따라 최적화된 방법을 선택하는 것이 중요합니다. 관련 질문 링크
Swift Concurrency에서도 task가 다른 스레드나 CPU에서 재개될 때 context switch가 필요합니다. 그러나 Swift Concurrency는 이러한 작업들을 자동으로 관리하며, 특히 async/await 패턴은 개발자가 이러한 세부사항을 신경쓸 필요 없이 동시성을 관리할 수 있도록 돕습니다. Context switching 자체는 비용이 들지만, Swift Concurrency는 비효율성을 최소화하도록 최적화된 내부 메커니즘을 가지고 있습니다. 관련 질문 링크
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.