2025. 7. 30. 13:44ㆍ프로그래밍/Rust
새로운 일을 시작하면서 Slint를 처음으로 사용해보았습니다.
Rust에서 본격적으로 개발을 하다 보면 Tokio와 Task를 피해갈 수가 없습니다. 상당히 많은 라이브러리들이 비동기를 기본으로 지원하다 보니 거기에 맞추어 개발을 할 수 밖에 없는데요. 개별적으로 동작하는 Task 사이에 데이터를 공유하자면 Arc<Mutex<T>>를 사용하여 변수를 공유하거나 채널을 사용하여 데이터를 전달하게 됩니다.
Arc<Mutex<T>>를 사용하기 시작하면 deadlock 발생 확률이 생깁니다. Rust가 좋은 언어이지만 deadlock 발생 가능성까지는 컴파일러에서 알아채지 못합니다. 조금만 주의를 잃어도 lock이 걸린 상태에서 다시 lock을 시도하는 등의 잘못된 코드를 작성하게 되고, 컴파일러는 오류 메세지 없이 빌드해내지만 실행해보면 어디선가 루프가 멈추는 상황이 발생하는데 추적이 쉽지 않습니다.
Channel을 사용하게 되면 간단히 tx 데이터를 써넣고, 데이터를 읽는 측에서는 비동기 상태로 대기하다가 rx를 통해 데이터를 읽을 수 있을 때에만 반응하면 됩니다. Channel을 사용할 때의 문제점이라면 이렇게 각 컴포넌트 간에 명시적인 연결 지점이 생기게 되고, 그로인한 의존성이 생긴다는 것과 채널들이 많아지면 각 채널들의 이름을 정하는 것부터 어디서 데이터가 오고 가는 것인지에 대해 판단하기가 간단하지 않게 됩니다.
이 정도쯤 되면 세상에 더 좋은 방법이 있을 거라고 생각하게 됩니다. 그래서 더 좋은 해결책을 찾다보니 Actor 모델을 찾게 되었습니다.
Actor 모델에 대해서 더 필요성을 느꼈던 것 중에 하나는 Bevy Engine에서 Plugin 단위로 컴포넌트를 만들어 사용하면서 각각의 컴포넌트들이 자신에 대한 통제권을 가지고 외부와 격리된 채로 최소한의 필요한 데이터만 주고 받게 만드는 것의 장점을 알게 되었기 때문입니다.
- 동시에 여러 사람이 하나의 프로젝트에서 작업을 하더라도 다른 요소에 대한 개발을 한다면 코드가 충돌하는 상황이 줄어듭니다.
- 서로 간의 의존성이 낮기 때문에 코드를 이해하기도 쉬워집니다.
- 이벤트의 추상화가 잘 되어 있다면 컴포넌트를 다른 것으로 교체하는 일도 쉬워집니다.
이런 장점들이 기존 프로젝트를 Actor 모델로 재구성하면서 발생하는 복잡도를 감당할 만큼은 된다는 생각이 들었습니다. 특히 slint를 사용해보니 Actor 모델을 적용하는 것이 UI를 제어하거나 UI에서 발생한 이벤트를 처리하기에 더 좋겠다는 생각이 들더라구요.
처음 Slint를 써 보시는 분들 보다는 Slint를 사용해서 본격적인 프로젝트를 제작하시는 분들이 Actor 모델을 적용할 수 있도록 참고할만한 예제를 만들었습니다.
https://github.com/cellaxon/slint_and_kameo_test
이게 생각보다 파일과 폴더의 개수가 많아져서 프로젝트를 생성하고 각 파일을 만드는 과정을 모두 기록하기에는 어렵네요. 기본적인 아이디어와 데이터의 흐름에 대한 설명만 남겨두겠습니다.
기본적인 구성은 다음과 같습니다.
- Slint UI : 화면에 표시되는 GUI 요소
- UI Actor : Slint UI에서 보내오는 메세지에 대한 처리와 UI Actor에서 받은 UI 제어 메세지를 Slint UI에 전달하는 Acotr
- Core Actor : 비지니스 로직이 동작하는 Actor
프로젝트에서 발생하는 이벤트의 흐름은 다음과 같습니다.
- Slint 에서 발생하는 UI 이벤트는 callback 함수를 통해 처리합니다. 이 때 callback 함수에 UI Actor에 대한 레퍼런스를 남겨두어 이벤트가 발생할 때 UI Actor에 메세지를 전달하도록 했습니다.
- UI Actor는 Slint UI로부터 받은 메세지를 Core Actor에 전달합니다.
- Core Actor는 받은 메세지를 처리하고 UI Actor에 처리한 결과를 전달합니다.
- UI Actor는 Core Actor로부터 받은 데이터를 Slint UI로 전달합니다.
이 구조를 기초로 해서 기능들을 확장해간다면 프로젝트가 더 커지더라도 이해와 관리가 더 나아질 것으로 생각하고 있습니다.
덧붙임.
Actor 모델이 silver bullet 같은 것은 아닙니다. 여러 단계의 데이터 중계 과정이 추가되기 때문에 그에 따라 추가해야 할 정의들이 늘어나고, 송신과 수신 처리에 대한 코드를 추가하면서 복잡해지는 부분이 있습니다. 다만 공유 변수 사용으로 인해 실수가 발생할 수 있는 여지를 줄이고, 개별 요소들을 잘 격리하게 됨으로 해서 생기는 장점들이 단점을 상쇄할 수 있다면 충분히 도입할 가치가 있어 보입니다.
'프로그래밍 > Rust' 카테고리의 다른 글
Rust + Bevy Engine + egui 시작하기 (0) | 2025.07.30 |
---|---|
[macOS] PyO3를 사용하여 rust에서 python 코드를 실행하기 (0) | 2025.02.25 |
opencv 비디오 파일의 영상 표시(rust/macos) (0) | 2024.08.28 |
opencv with rust in windows (0) | 2024.08.27 |
Rust / 문자열 입력 (0) | 2022.12.29 |