Rust

다메즈마 (토론 | 기여)님의 2017년 12월 10일 (일) 02:53 판

Rust is a systems programming language that runs blazingly fast, prevents nearly all segfaults, and guarantees thread safety.

Rust는 매우 빠르며, 세그폴트를 방지하고, 스레드 안전성을 보장하는 시스템 프로그래밍 언어입니다.
— 러스트 공식 홈페이지

Rust(러스트)는 모질라 재단에서 제작중인 프로그래밍언어이다. 2017년 12월 10일 기준 최신버전은 1.22.1이다

Rust의 제작방향

모질라 재단에서 왜 굳이 새로운 언어를 만들어야 했는가? 그 이유는 기존 프로그래밍 언어들에게 각각의 단점이 있었기 때문이다.

우선 모질라 재단의 주력 소프트웨어는 파이어폭스이다. 이 파이어폭스에서 OS의 커널과 비견될만한 것이 Gecko엔진이다. 하지만 이 Gecko엔진은 아직 멀티 프로세싱이 개인에게 보급되기 전인 2000년대에 만들어졌기 때문에 싱글 프로세스 기준으로 제작되었으며, 기본적으로 렌더링이든, 자바스크립트의 작동이든, 부가기능이든 Gecko엔진에서 전부 처리되는 시스템이여서 Gecko엔진에 부담이 몰려있는 구조이다.

거기다 구글의 Chrome, MS사의 인터넷익스플로러 및 엣지가 무서울 정도로 빠른 성능적인 발전을 이뤘고, 이에 따라 파이어폭스의 점유율이 낮아지기 시작했다.

이러한 상황에서 모질라재단은 성능의 향상을 위해서 새로운 엔진을 제작하기로 마음을 먹었다. 그러나 이러한 새로운 엔진 제작에 발목을 잡는게 있었다 바로 예산이다.

새로운 엔진을 제작할 때 프로그래밍 언어의 선택은 매우 중요하다. 엔진의 실행속도, 제작속도 및 제작의 용이성이 아주 중요하기 때문이다.

  • 우선 C++의 경우 엔진의 실행속도를 잡을 수는 있으나, 제작속도및 용이성에서 아주 떨어지는 문제점이 있었다. 새로운 엔진을 제작할 때는 멀티 프로세싱을 하기 위해서 쓰레드를 사용해야 하는데 C++의 쓰레드는 숙련된 C++ 프로그래머가 아니면 사용하기가 매우 어렵고, 숙련된 C++프로그래머의 몸값은 매우 비싸다
  • Java의 경우 쓰레드의 사용은 C++보다 용이하고 메모리 관리 또한 C++보다 편한 면이 있으나, 기본적으로 Java의 경우 가상머신 위에서 돌기 때문에 속도가 느리다라는 점이 있어 새로운 엔진에 사용하기가 곤란했다.
  • C#의 경우 Java와 비슷한 장단점이 있으나, 기본적으로 MS에 종속되어 있어서 역시 곤란했다.
  • 기타 스크립트 언어들은 이러한 무거운 프로그램을 제작하는데 적합하기 않았다.

한편 이러한 기존 언어들은 장단점이 있어서 곤란할 때, 모질라는 역발상을 하게 되었다

어차피 이렇게 된거 C++보다 메모리 관리가 용이하고 쓰레드의 사용이 쉬운 언어를 만들자!

한편, 모질라 소속의 개발자였던 그레이던 호어의 개인 프로젝트였던 Rust를 매의 눈으로 발견하고 이를 지원하게 되었다.

기능

  • 비용 없는 추상화
  • 이동(move) 의미론
  • 메모리 안전성 보장
  • 데이터 레이스 없는 스레딩
  • 트레이트 기반 일반화(generic)
  • 패턴 매칭
  • 타입 추론
  • 최소한의 런타임
  • 효율적인 C 바인딩

특징

이러한 사정으로 개발이 시작된 Rust이기 때문에 C++의 단점을 보완하기 위한 몇가지 특징이 존재한다.

C/C++과 대등한 퍼포먼스

C/C++를 대체하기 위해서 만들어진 Rust이므로 같은 환경, 같은 조건에서는 비교적 C/C++과 거의 동등한 퍼포먼스를 보인다.출처

바이너리 트리

언어 조건 수행시간 메모리 사용량
Rust 20 4.17sec 128,036KB
C++ 20 6.98sec 150,512KB
C 20 3.28sec 156,780KB
Go 20 48.57sec 322,256KB

mandelbrot

언어 조건 수행시간 메모리 사용량
Rust 16,000 5.60sec 69,452KB
C++ 16,000 5.82sec 33,952KB
C 16,000 5.92sec 32,572KB
Go 16,000 6.44sec 32,044KB

변수의 기본은 상수

변수는 기본적으로 상수(바꿀 수 없는 상태)이다. 처음에 선언했을 때의 값을 가지고 계속 보존하고 있으며, 코드 중간에 값을 수정하는 일을 금지한다. 물론 모든 변수가 상수이면, 프로그래밍을 짜기 어렵기 때문에, 변수를 선언할 때, mut이라는 키워드를 넣어주면 변수의 값을 중간에 바꿀 수 있다.

fn main() {
    let a = 5;
    println!("{}", a);
    a = 10;
    println!("{}", a);
}

이러한 코드는 Rust에서는 동작할 수 없다. Rust에서는 기본적으로 모든 변수는 변경불가가 기본상태이기 때문이다. 따라서 mut키워드를 추가해 줘야 한다.

fn main() {
    let mut a = 5;
    println!("{}", a);
    a = 10;
    println!("{}", a);
}

Rust에서 기본 변수의 상태를 변경불가로 둔 것은 멀티 프로세싱과 메모리 안정성에 중요도를 둔 결과다. 멀티프로세싱에서 제일 문제가 되는 것은 여러 스레드에서 한 데이터를 접근할 때인데 기본 상태를 변경 불가로 두면, 데이터의 수정을 제한 시킬 수 있으므로, 스레드의 데이터 변경에 의한 문제를 미리 방지할 수 있고, 최적화 또한 쉽게 이룰수 있으며, 문제가 생기더라도 확인해야 하는 구간이 적어진다.

변수의 소유권과 레퍼런스

다른 프로그래밍 언어에선 쉽게 볼 수 없는 개념으로서 소유권이라는 개념이 있다. 소유권과 레퍼런스의 규칙은 다음과 같다.

  1. Rust의 모든 변수의 소유자는 기본적으로 변수가 생성된 범위(scope)이며, 변수는 소유자가 끝나면 해제가 된다.
  2. 변수를 인자로 넘길 때, 변수의 소유권또한 같이 넘어간다.
  3. 변수의 참조 변수(reference)가 있을 때, 참조 변수는 변수가 해제되기 전에 먼저 해제되어야 한다.
  4. 기본적으로 참조 변수는 변수의 값을 수정할 수 없으며(immutable), 수정하려면 수정가능한 레퍼런스를 받아야 한다 (mutable refernce)
  5. 수정가능한 레퍼런스를 받을 때는 다른 레퍼런스 변수들이 존재해서는 안된다.

쓰레기 수집(Garbage Collection)없는 안정적인 메모리 해제

변수의 소유권과 레퍼런스 이라는 특징으로 프로세스 실행 중에 쓰레기 수집없이, 사용자가 해제코드를 넣지 않더라도 안정적인 메모리 해제를 한다.

강타입 언어, 명시적인 형변환

C/C++의 int <-> float 혹은 unsigned int <-> int 같의 암시적인 형변환이 이루어 지는 것에 비해, Rust는 명시적인 형변환이 없는 한, 타입이 다른 형식끼리의 연산이 에러로 처리된다.

Cargo를 이용한 라이브러리 관리

node.js의 NPM이나 Visual Studio의 Nuget처럼 Rust는 컴파일 도구를 설치할 때, 라이브러리 관리 툴로서 Cargo를 이용한다. 라이브러리를 crate라고 부르며, 라이브러리 목록은 https://crates.io/에서 볼 수 있다.

저도 사용해볼래요!

만약 Rust를 이용해 프로그래밍을 한 번 해보고 싶다면, Rust/튜토리얼 항목으로 가 보자.

Rust를 이용한 소프트웨어

외부 링크

각주

  1. 드롭박스의 file storage system
  2. Rust로 작성된 모듈이 48버전부터 추가되었다
  3. 일부 모듈 제작에 사용됨