Rust는 화려하게 빠르게 실행하고 Segfaults를 방지하며 스레드 안전을 보장하는 시스템 프로그래밍 언어입니다.
특징
가져온 : Rust-lang.org에서
엘리아스 로부터 회원과 Rust Brazil Telegram Group 의 Rust Guru 에 대한 더 나은 설명
Rust는 높은 수준의 추상화를 구축 할 수있는 언어이지만, 낮은 수준 제어를 포기하지 않고, 즉 메모리에 데이터가 어떻게 표현되는지, 사용하려는 스레딩 모델의 제어 등을 제어하는 언어입니다 .
Rust는 일반적으로 컴파일 중에 최악의 병렬 처리 및 메모리 관리 오류 (예 : 동기화없이 다른 스레드의 데이터에 액세스하거나 거래 후 데이터를 사용하는 등)를 감지 할 수있는 언어이지만 실제로 수행하는 작업을 알고있는 경우 해치 탈출을 제공합니다.
Rust는 런타임이 없기 때문에 모든 런타임과 통합하는 데 사용할 수있는 언어입니다 . 프로그램 Node.js 또는 Python 프로그램 또는 Ruby, LUA 등의 프로그램에 의해 불리는 Rust에서 기본 확장을 작성할 수 있으며 반면 에이 언어를 사용하여 Rust로 프로그램을 스크립트 할 수 있습니다. - "Elias Gabriel Amaral da Silva"

Python을 녹으로 확장하는 데 도움이되는 Rust 패키지가 많이 있습니다.
Armin Ronacher (플라스크 제작자)와 Pyo3 Python 통역사의 녹 바인딩이 만든 Milksnake를 언급 할 수 있습니다.
하단의 전체 참조 목록을 참조하십시오.
이 게시물의 경우 Rust Cpython을 사용하려고합니다. 테스트 한 유일한 사람이며, Rust의 안정적인 버전 과 호환되며 사용하기가 간단합니다.
참고 : PYO3은 Rust-Cpython의 포크이며 많은 개선 사항이 있지만 야간 버전의 Rust 와만 작동 하므로이 게시물의 안정적인 제품을 사용하는 것이 선호되었으므로 여기의 예제는 PYO3에서도 작동해야합니다.
장점 : Python에서 Rust Functions를 작성하고 가져 오는 것은 정말 쉽고 성능 측면에서 가치가있는 벤치 마크에서 볼 수 있습니다.
단점 : 프로젝트/lib/프레임 워크 의 분포는 환경과 아키텍처의 변형으로 인해 Target 시스템에서 Rust 모듈을 컴파일해야합니다. 순수한 파이썬 라이브러리를 설치할 때없는 컴파일 단계가있을 것입니다. Rust-setuptools를 사용하거나 Milksnake를 사용하여 Python 휠에 이진 데이터를 더 쉽게 사용할 수 있습니다.
예, Python은 경우에 따라 "느린"것으로 알려져 있으며 좋은 소식은 프로젝트 목표와 우선 순위에 따라 중요하지 않다는 것입니다. 대부분의 프로젝트 에서이 세부 사항은 그리 중요하지 않습니다.
그러나 단일 기능이나 모듈이 너무 많은 시간이 걸리고 프로젝트 성능의 병목 현상으로 감지되는 드문 경우에 직면 할 수 있습니다. 종종 문자열 구문 분석 및 이미지 처리에서 발생합니다.
어떤 종류의 문자열 처리를 수행하는 Python 함수가 있다고 가정 해 보겠습니다. counting pairs of repeated chars 하는 다음과 같은 쉬운 예를 들어이 예제는 다른 string processing 기능 또는 Python의 다른 일반적으로 느린 프로세스로 재현 할 수 있음을 명심하십시오.
# How many subsequent-repeated group of chars are in the given string?
abCCdeFFghiJJklmnopqRRstuVVxyZZ... {millions of chars here}
1 2 3 4 5 6 Python은 큰 string 처리를 수행하는 데 매우 느리기 때문에 pytest-benchmark 사용하여 Pure Python (with Iterator Zipping) 기능과 Regexp 구현을 비교할 수 있습니다.
# Using a Python3.6 environment
$ pip3 install pytest pytest-benchmark
그런 다음 doubles.py 라는 새로운 Python 프로그램을 작성하십시오
import re
import string
import random
# Python ZIP version
def count_doubles ( val ):
total = 0
for c1 , c2 in zip ( val , val [ 1 :]):
if c1 == c2 :
total += 1
return total
# Python REGEXP version
double_re = re . compile ( r'(?=(.)1)' )
def count_doubles_regex ( val ):
return len ( double_re . findall ( val ))
# Benchmark it
# generate 1M of random letters to test it
val = '' . join ( random . choice ( string . ascii_letters ) for i in range ( 1000000 ))
def test_pure_python ( benchmark ):
benchmark ( count_doubles , val )
def test_regex ( benchmark ):
benchmark ( count_doubles_regex , val )pytest를 실행하여 비교하십시오.
$ pytest doubles.py
=============================================================================
platform linux -- Python 3.6.0, pytest-3.2.3, py-1.4.34, pluggy-0.4.
benchmark: 3.1.1 (defaults: timer=time.perf_counter disable_gc=False min_roun
rootdir: /Projects/rustpy, inifile:
plugins: benchmark-3.1.1
collected 2 items
doubles.py ..
-----------------------------------------------------------------------------
Name (time in ms) Min Max Mean
-----------------------------------------------------------------------------
test_regex 24.6824 (1.0) 32.3960 (1.0) 27.0167 (1.0)
test_pure_python 51.4964 (2.09) 62.5680 (1.93) 52.8334 (1.96)
-----------------------------------------------------------------------------
비교를위한 Mean 을 취할 수 있습니다.
상자 는 우리가 Rust Packages라고 부르는 방법입니다.
Rust를 설치 한 상태 (권장 방법은 https://www.rustup.rs/) Fedora 및 Rhel Rust-Toolset에서도 사용할 수 있습니다.
rustc 1.21.0사용했습니다
동일한 폴더에서 실행 :
cargo new pyext-myrustlib Cargo.toml (Cargo is Rust Package Manager) 및 src/lib.rs (라이브러리 구현을 작성하는 위치)를 포함하는 pyext-myrustlib 라는 동일한 폴더에서 새로운 Rust 프로젝트를 만듭니다.
rust-cpython 상자를 의존성으로 사용하고화물에게 파이썬에서 가져올 dylib 생성하도록 지시합니다.
[ package ]
name = " pyext-myrustlib "
version = " 0.1.0 "
authors = [ " Bruno Rocha <[email protected]> " ]
[ lib ]
name = " myrustlib "
crate-type = [ " dylib " ]
[ dependencies . cpython ]
version = " 0.1 "
features = [ " extension-module " ]우리가해야 할 일 :
cpython Crate에서 모든 매크로를 가져 오십시오
Cpython에서 Lib 범위까지 Python 및 PyResult 유형을 가져 가십시오.
count_doubles 기능 구현을 Rust 에 작성하십시오. 이것은 다음을 제외하고 Pure Python 버전과 매우 유사합니다.
Python 첫 번째 인수로 받아들이며, 이는 Python 통역사에 대한 참조이며 Rust가 Python GIL 사용할 수 있도록합니다.&str 타이핑 val 참조로받습니다PyResult 반환합니다.PyResult 객체를 Ok(total) 로 반환합니다 ( 결과는 성공 (OK) 또는 실패 (ERR)를 나타내는 열거 형식이며, 기능이 PyResult 반환 할 것으로 예상되면 컴파일러는 해당 유형의 Ok 감싸는 것을 관리합니다. (우리의 pyresult는 u64 반환 값으로 기대합니다) py_module_initializer! 매크로 우리는 __doc__ 포함하여 lib에 새로운 속성을 등록하고 또한 Rust implementation of the function 참조하는 count_doubles 속성을 추가합니다.
try! 파이썬의 try.. exceptOk(()) - () 는 빈 결과 튜플이며 파이썬에서 None 과 동일합니다. # [ macro_use ]
extern crate cpython ;
use cpython :: { Python , PyResult } ;
fn count_doubles ( _py : Python , val : & str ) -> PyResult < u64 > {
let mut total = 0u64 ;
for ( c1 , c2 ) in val . chars ( ) . zip ( val . chars ( ) . skip ( 1 ) ) {
if c1 == c2 {
total += 1 ;
}
}
Ok ( total )
}
py_module_initializer ! ( libmyrustlib , initlibmyrustlib , PyInit_myrustlib , | py , m | {
try ! ( m . add ( py , " __doc__ " , " This module is implemented in Rust " ) ) ;
try! ( m . add ( py , " count_doubles " , py_fn ! ( py , count_doubles ( val : & str ) ) ) ) ;
Ok ( ( ) )
} ) ;이제화물에 구축하겠습니다
$ cargo build --release
Finished release [optimized] target(s) in 0.0 secs
$ ls -la target/release/libmyrustlib *
target/release/libmyrustlib.d
target/release/libmyrustlib.so * < -- Our dylib is here 이제 생성 된 .so lib를 doubles.py 있는 동일한 폴더에 복사 할 수 있습니다.
참고 : Fedora 에서는 다른 시스템에서는
.so.dylib얻을 수 있으며 확장 변경을.so로 변경할 수 있습니다.
$ cd ..
$ ls
doubles.py pyext-myrustlib/
$ cp pyext-myrustlib/target/release/libmyrustlib.so myrustlib.so
$ ls
doubles.py myrustlib.so pyext-myrustlib/
myrustlib.so사용하여 동일한 폴더에 있거나 Python 경로에 추가하면 Python 모듈이므로 투명하게 직접 가져올 수 있습니다.
doubles.py Rust implemented 편집하십시오 benchmark
import re
import string
import random
import myrustlib # <-- Import the Rust implemented module (myrustlib.so)
def count_doubles ( val ):
"""Count repeated pair of chars ins a string"""
total = 0
for c1 , c2 in zip ( val , val [ 1 :]):
if c1 == c2 :
total += 1
return total
double_re = re . compile ( r'(?=(.)1)' )
def count_doubles_regex ( val ):
return len ( double_re . findall ( val ))
val = '' . join ( random . choice ( string . ascii_letters ) for i in range ( 1000000 ))
def test_pure_python ( benchmark ):
benchmark ( count_doubles , val )
def test_regex ( benchmark ):
benchmark ( count_doubles_regex , val )
def test_rust ( benchmark ): # <-- Benchmark the Rust version
benchmark ( myrustlib . count_doubles , val )$ pytest doubles.py
==============================================================================
platform linux -- Python 3.6.0, pytest-3.2.3, py-1.4.34, pluggy-0.4.
benchmark: 3.1.1 (defaults: timer=time.perf_counter disable_gc=False min_round
rootdir: /Projects/rustpy, inifile:
plugins: benchmark-3.1.1
collected 3 items
doubles_rust.py ...
-----------------------------------------------------------------------------
Name (time in ms) Min Max Mean
-----------------------------------------------------------------------------
test_rust 2.5555 (1.0) 2.9296 (1.0) 2.6085 (1.0)
test_regex 25.6049 (10.02) 27.2190 (9.29) 25.8876 (9.92)
test_pure_python 52.9428 (20.72) 56.3666 (19.24) 53.9732 (20.69)
----------------------------------------------------------------------------- 비교를위한 Mean 을 취할 수 있습니다.
Rust 구현은 Python Regex보다 10 배 빠르고 Pure Python 버전보다 21 배 빠를 수 있습니다.
REGEX 버전은 순수한 파이썬보다 2 배 빠릅니다. :)
참고 :이 숫자는이 특정 시나리오에 대해서만 의미가 있으며, 다른 경우에는 비교가 다를 수 있습니다.
이 기사가 출판 된 후 R/Python과 R/Rust에 대한 의견을 받았습니다.
기부금은 풀 요청으로 제공되며 기능을 개선 할 수 있다고 생각되면 새로운 것을 보낼 수 있습니다.
감사합니다 : Josh Stone은 Rust를위한 더 나은 구현 구호를 얻었습니다.
감사합니다 : Purple Pixie itertools 사용하여 Python 구현을 받았지만이 버전은 더 나은 성능을 발휘하지 않으며 개선이 필요합니다.
fn count_doubles_once ( _py : Python , val : & str ) -> PyResult < u64 > {
let mut total = 0u64 ;
let mut chars = val . chars ( ) ;
if let Some ( mut c1 ) = chars . next ( ) {
for c2 in chars {
if c1 == c2 {
total += 1 ;
}
c1 = c2 ;
}
}
Ok ( total )
} def count_doubles_once ( val ):
total = 0
chars = iter ( val )
c1 = next ( chars )
for c2 in chars :
if c1 == c2 :
total += 1
c1 = c2
return total import itertools
def count_doubles_itertools ( val ):
c1s , c2s = itertools . tee ( val )
next ( c2s , None )
total = 0
for c1 , c2 in zip ( c1s , c2s ):
if c1 == c2 :
total += 1
return total 자,이 게시물의 목적이 아닙니다.이 게시물은 Rust X other language 비교하는 것이 아니 었습니다.이 게시물은 Rust를 사용하여 Python을 확장하고 속도를 높이는 방법 에 관한 것이 었으며,이를 통해 other language 대신 Rust를 선택하거나 안전과 도구를 따라 가거나 단순히 Rust를 따르는 것이 중요하지 않기 때문에 Rust 를 따라야합니다.
나는 (개인적으로) Rust가 새롭기 때문에 더 future proof 라고 말할 수 있으며 생태계, 툴링 및 커뮤니티로 인해 Rust 구문에 익숙하기 때문에 많은 개선 사항이 있습니다.
따라서 사람들이 다른 언어의 사용에 대해 불평하기 시작했고 일종의 벤치 마크가되어 멋지다고 생각합니다!
따라서 개선 요청의 일환으로 Hacker News의 일부 사람들도 아이디어를 보냈으며 Martinxyz는 C와 SWIG를 사용하여 구현을 보냈습니다.
C 코드 (Swig Boilerplate omited)
uint64_t count_byte_doubles ( char * str ) {
uint64_t count = 0 ;
while ( str [ 0 ] && str [ 1 ]) {
if ( str [ 0 ] == str [ 1 ]) count ++ ;
str ++ ;
}
return count ;
} 그리고 우리의 동료 Red Hatter Josh Stone은 chars bytes 로 교체함으로써 Rust 구현을 다시 향상 시켰으므로 C가 유니 코드 숯 대신 바이트를 비교함에 따라 C 와의 공정한 경쟁입니다.
fn count_doubles_once_bytes ( _py : Python , val : & str ) -> PyResult < u64 > {
let mut total = 0u64 ;
let mut chars = val . bytes ( ) ;
if let Some ( mut c1 ) = chars . next ( ) {
for c2 in chars {
if c1 == c2 {
total += 1 ;
}
c1 = c2 ;
}
}
Ok ( total )
} Python list comprehension 과 numpy 비교하는 아이디어도 있습니다.
Numpy :
import numpy as np
def count_double_numpy ( val ):
ng = np . fromstring ( val , dtype = np . byte )
return np . sum ( ng [: - 1 ] == ng [ 1 :])이해력을 나열하십시오
def count_doubles_comprehension ( val ):
return sum ( 1 for c1 , c2 in zip ( val , val [ 1 :]) if c1 == c2 ) 전체 테스트 케이스는 저장소 test_all.py 파일에 있습니다.
-------------------------------------------------------------------------------------------------
Name (time in us) Min Max Mean
-------------------------------------------------------------------------------------------------
test_rust_bytes_once 476.7920 (1.0) 830.5610 (1.0) 486.6116 (1.0)
test_c_swig_bytes_once 795.3460 (1.67) 1,504.3380 (1.81) 827.3898 (1.70)
test_rust_once 985.9520 (2.07) 1,483.8120 (1.79) 1,017.4251 (2.09)
test_numpy 1,001.3880 (2.10) 2,461.1200 (2.96) 1,274.8132 (2.62)
test_rust 2,555.0810 (5.36) 3,066.0430 (3.69) 2,609.7403 (5.36)
test_regex 24,787.0670 (51.99) 26,513.1520 (31.92) 25,333.8143 (52.06)
test_pure_python_once 36,447.0790 (76.44) 48,596.5340 (58.51) 38,074.5863 (78.24)
test_python_comprehension 49,166.0560 (103.12) 50,832.1220 (61.20) 49,699.2122 (102.13)
test_pure_python 49,586.3750 (104.00) 50,697.3780 (61.04) 50,148.6596 (103.06)
test_itertools 56,762.8920 (119.05) 69,660.0200 (83.87) 58,402.9442 (120.02)
-------------------------------------------------------------------------------------------------
new Rust implementation comparing bytes 기존 유니 코드 chars 보다 2 배 더 좋습니다.Rust 버전은 Swig를 사용하는 C 보다 여전히 낫습니다.unicode chars 비교하는 Rust 여전히 numpy 보다 낫습니다Numpy 유니 코드 숯에 대한 이중 반복 문제가있는 first Rust implementation 보다 낫습니다.list comprehension 사용하면 pure Python 사용하는 것보다 중요한 차이가 없습니다.참고 : 변경 사항 또는 개선 사항을 제안하려면 PR을 여기에서 보내십시오 : https://github.com/rochacbruno/rust-python-example/
Pull 요청이 Jason Knight가 Rust 사용하여 Rust를 향상시키기 위해 더 많은 기여를 받았습니다.
RUSTFLAGS= " -C target-cpu=native " cargo build --release 그리고 numba 와의 비교에 대해 궁금한 사람들을 위해 Shyba는 그것을 구현했으며 Numba 지점 https://github.com/rochacbruno/rust-python-example/tree/numba에서 사용할 수 있습니다.
from numba import jit
@ jit ( nopython = True , cache = True )
def count_doubles_once_numba ( val ):
total = 0
chars = iter ( val )
c1 = next ( chars )
for c2 in chars :
if c1 == c2 :
total += 1
c1 = c2
return totalNumba가 맨 위에있는 새로운 결과를 봅니다 .
----------------------------------------------------------------------------------------------------
Name (time in us) Min Max Mean
----------------------------------------------------------------------------------------------------
test_pure_python_once_numba 292.0990 (1.0) 317.7590 (1.0) 296.7477 (1.0)
test_numpy_numba 326.2470 (1.12) 526.1350 (1.66) 338.1704 (1.14)
test_rust_bytes_once 336.0620 (1.15) 1,053.0090 (3.31) 342.5122 (1.15)
test_c_swig_bytes_once 375.6310 (1.29) 1,389.9070 (4.37) 388.9181 (1.31)
test_rust_once 986.0360 (3.38) 2,498.5850 (7.86) 1,006.5819 (3.39)
test_numpy 1,137.1750 (3.89) 2,000.5430 (6.30) 1,167.2551 (3.93)
test_rust 2,555.1400 (8.75) 3,645.3900 (11.47) 2,592.0419 (8.73)
test_regex 22,597.1750 (77.36) 25,027.2820 (78.76) 22,851.8456 (77.01)
test_pure_python_once 32,418.8830 (110.99) 34,818.0800 (109.57) 32,756.3244 (110.38)
test_pure_python 43,823.5140 (150.03) 45,961.8460 (144.64) 44,367.1028 (149.51)
test_python_comprehension 46,360.1640 (158.71) 50,578.1740 (159.17) 46,986.8058 (158.34)
test_itertools 49,080.8640 (168.03) 51,016.5230 (160.55) 49,405.2562 (166.49)
---------------------------------------------------------------------------------------------------- 그리고 Mike Fletcher의 Cython 구현도 cython https://github.com/rochacbruno/rust-python-example/tree/cython의 Cython 구현도 있습니다.
결과와 함께 :
----------------------------------------------------------------------------------------------------
Name (time in us) Min Max Mean
----------------------------------------------------------------------------------------------------
test_rust_bytes_once 336.7590 (1.0) 806.2610 (1.0) 346.5317 (1.0)
test_cython 756.1610 (2.25) 2,343.3680 (2.91) 785.6455 (2.27)
test_c_swig_bytes_once 802.4250 (2.38) 1,632.4290 (2.02) 840.8603 (2.43)
----------------------------------------------------------------------------------------------------이 게시물의 목적으로 돌아가서 우리가 시작한 Rust로 파이썬 속도를 높이는 방법 :
이 예에서 Rust는 순수한 파이썬 보다 100 배 빠르게 수행되었습니다.
Rust 마술처럼 당신을 절약하지 못할 것이며, 영리한 솔루션을 구현할 수있는 언어를 알아야하고, 일단 오른쪽에서 성능면에서 C만큼 가치가 있으며 놀라운 툴링, 생태계, 커뮤니티 및 안전 보너스와 함께 제공됩니다.
Rust 아직 복잡한 수준에 의해 선택되는 general purpose language 아닐 수 있으며 web 사이트 및 test automation 스크립트와 같은 일반적인 간단한 applications 작성하는 것이 더 나은 선택이 아닐 수도 있습니다.
그러나 Python이 병목 현상으로 알려진 프로젝트의 specific parts 의 경우 자연스러운 선택이 C/C++ 확장을 구현하는 것이 C/C ++ 확장을 구현하는 것이 Rust로 작성하는 것이 쉽고 유지하기가 쉽고 더 나은 것처럼 보입니다.
녹슬고 많은 사람들이 Python <--> Rust 통합을 제공하기 위해 많은 개선 사항이 여전히 많습니다. 당신이 지금 당신의 도구 벨트에 언어를 포함시키지 않더라도, 미래에 주시를 계속할 가치가 있습니다!
이 간행물의 예는 Pycon Canada 의 Samuel Cormier-Iijima 의 Extending Python with Rust 영감을 얻었습니다. 비디오 : https://www.youtube.com/watch?v=-ylbuezkg4m
또한 내 파이썬은 Pycon Montreal 의 Dan Callahan 에 의해 My Python is a little Rust-y . 비디오 : https://www.youtube.com/watch?v=3CWJ0MH-4MA
기타 참조 :
커뮤니티에 가입 :
Rust Community에 가입하면 https://www.rust-lang.org/en-us/community.html에서 그룹 링크를 찾을 수 있습니다.
포르투갈어를 사용하는 경우 https://t.me/rustlangbr에 가입하는 것이 좋습니다. YouTube에는 http://bit.ly/canalrustbr도 있습니다.
브루노 로차
자세한 정보 : http://about.me/rochacbruno 및 http://brunorocha.org