두려움 없는 동시성

두려움 없는 동시성 (Fearless Concurrency)

동시성 프로그래밍을 안전하고 효율적으로 다루는 것은 Rust의 또 다른 주요 목표예요. 프로그램의 서로 다른 부분이 독립적으로 실행되는 동시성 프로그래밍과, 서로 다른 부분이 동시에 실행되는 병렬 프로그래밍은, 더 많은 컴퓨터가 여러 프로세서를 활용하면서 점점 더 중요해지고 있어요. 역사적으로 이런 맥락에서 프로그래밍하는 것은 어렵고 오류가 잦았죠. Rust는 그것을 바꾸려고 해요.

출처: The Rust Book

왜 소유권과 타입 시스템인가 (Why Ownership and Types)

처음에 Rust 팀은 메모리 안전을 보장하는 것과 동시성 문제를 막는 것이 서로 다른 방법으로 풀어야 할 두 가지 별개의 도전이라고 생각했어요. 시간이 지나면서 팀은 소유권과 타입 시스템이 메모리 안전과 동시성 문제를 관리하는 데 도움이 되는 강력한 도구 묶음이라는 걸 발견했습니다! 소유권과 타입 검사를 활용하면 많은 동시성 에러가 Rust에서 런타임 에러가 아니라 컴파일 타임 에러가 돼요. 따라서 런타임 동시성 버그가 발생하는 정확한 상황을 재현하는 데 많은 시간을 쏟게 하는 대신, 잘못된 코드는 컴파일을 거부하며 문제를 설명하는 에러를 보여줍니다. 그 결과 코드가 배포된 뒤가 아니라 작업하는 동안 고칠 수 있어요. 우리는 이 측면을 두려움 없는 동시성(fearless concurrency)이라고 불러요. 두려움 없는 동시성 덕분에 미묘한 버그가 없고, 새 버그를 도입하지 않고 리팩터링하기 쉬운 코드를 쓸 수 있습니다.

참고: 단순함을 위해, 정확하게 "동시적 그리고/또는 병렬적"이라고 말하는 대신 많은 문제를 "동시적"이라고 부를게요. 이 장에서는 우리가 "동시적"이라고 쓸 때마다 머릿속으로 "동시적 그리고/또는 병렬적"을 대입해 주세요. 그 구분이 더 중요한 다음 장에서는 더 정확하게 다룰게요.

많은 언어가 동시성 문제를 다루는 해결책에 대해 신념이 강해요. 예를 들어 Erlang은 메시지 전달 동시성에 우아한 기능이 있지만, 스레드 간 상태를 공유하는 데는 모호한 방법만 있어요. 가능한 해결책의 일부만 지원하는 것은 고수준 언어에게 합리적인 전략이에요. 고수준 언어는 어느 정도 제어를 포기해 추상화를 얻는 대가로 이득을 약속하니까요. 하지만 저수준 언어는 어떤 상황에서든 최상의 성능을 제공하는 해결책을 주고 하드웨어에 대한 추상화가 적어야 한다고 기대돼요. 그래서 Rust는 상황과 요구에 적절한 방식으로 문제를 모델링할 수 있도록 다양한 도구를 제공합니다.

이 장에서 다룰 주제는 이래요.

  • 동시에 여러 코드를 실행하기 위해 스레드를 만드는 방법
  • 채널이 스레드 간에 메시지를 보내는 메시지 전달 동시성
  • 여러 스레드가 어떤 데이터에 접근하는 공유 상태 동시성
  • Rust의 동시성 보장을 표준 라이브러리가 제공하는 타입뿐 아니라 사용자 정의 타입으로도 확장하는 SyncSend 트레이트

더 알아보기 (Learn more)

  • 16장의 다음 절에서 thread::spawn으로 스레드를 만들고, 채널로 메시지를 주고받는 방법을 살펴보세요.
  • Rust Reference: 동시성 — 스레드와 동시성 모델에 대한 공식 문서를 참고하세요.