"느린 동기 command는 앱을 얼려. async는 작업이 도는 동안 창이 계속 숨 쉬게 해."
그냥 async를 붙여
command를 비동기로 만들려면 async fn으로 써. Tauri가 그걸 async 런타임(Tokio)에서 돌리고, 프론트엔드의 invoke Promise는 future가 완료될 때 resolve돼. 이게 중요한 건 긴 동기 command가 블록해서 UI가 얼어붙은 느낌을 줄 수 있어서야. 네트워크 호출, 자식 프로세스 대기, I/O 바운드 뭐든 — async로 만들면 앱이 반응성을 유지해.
I/O 바운드 vs CPU 바운드
진짜 구분이 있어. I/O 바운드 작업(HTTP, 디스크, 대기)은 async에 완벽히 맞아 — 런타임이 기다리는 동안 태스크를 주차하고 다른 일을 돌려. CPU 바운드 작업(거대한 이미지 리사이즈, 해싱, 무거운 파싱)은 async만으론 이득이 없어. async 태스크 안에서 CPU를 갈면 여전히 런타임을 멈출 수 있어. 무거운 연산은 tokio::task::spawn_blocking(또는 그냥 std::thread)으로 블로킹 스레드에 떠넘겨서 async 런타임을 자유롭게 둬.
Send 함정
컴파일러가 강제할 규칙 하나: async command에서 await를 가로질러 들고 있는 데이터는 스레드 사이로 옮겨도 안전(Send)해야 해. 흔한 함정이 std::sync::Mutex 가드를 await 지점을 가로질러 들고 있는 거야 — 컴파일 안 돼. 고침은 await 전에 락을 떨구거나, async 인식 락을 쓰는 거야. state 트랙에서 제대로 만나 — 지금은 'cannot be sent between threads safely'가 보통 'await를 가로질러 락을 들고 있었다'는 뜻인 걸 알아둬.