Rust adalah bahasa pemrograman sistem yang berjalan sangat cepat, mencegah segfault, dan menjamin keamanan utas.
Menampilkan
Diambil dari: dari rust-lang.org
Deskripsi yang lebih baik tentang karat yang saya dengar dari Elias seorang anggota dan Guru Rust dari Rust Brasil Telegram Group
Rust adalah bahasa yang memungkinkan Anda untuk membangun abstraksi tingkat tinggi, tetapi tanpa melepaskan kontrol tingkat rendah - yaitu, kontrol bagaimana data diwakili dalam memori, kontrol model threading mana yang ingin Anda gunakan dll.
Rust adalah bahasa yang biasanya dapat mendeteksi, selama kompilasi, kesalahan paralelisme terburuk dan kesalahan manajemen memori (seperti mengakses data pada berbagai utas tanpa sinkronisasi, atau menggunakan data setelah mereka dialokasikan), tetapi memberi Anda lubang esket jika Anda benar -benar tahu apa yang Anda lakukan.
Rust adalah bahasa yang, karena tidak memiliki runtime, dapat digunakan untuk berintegrasi dengan runtime apa pun; Anda dapat menulis ekstensi asli dalam karat yang disebut oleh program node.js, atau oleh program Python, atau oleh program di Ruby, Lua dll. Dan, di sisi lain, Anda dapat membuat skrip program dalam karat menggunakan bahasa -bahasa ini. - "Elias Gabriel Amaral da Silva"

Ada banyak paket karat di luar sana untuk membantu Anda memperpanjang ular piton dengan karat.
Saya dapat menyebutkan milksnake yang dibuat oleh Armin Ronacher (pencipta labu) dan juga pyo3 binding karat untuk penafsir python
Lihat daftar referensi lengkap di bagian bawah.
Untuk posting ini, saya akan menggunakan Rust Cpython, ini satu -satunya yang saya uji, itu kompatibel dengan versi karat yang stabil dan ternyata mudah digunakan.
CATATAN : PYO3 adalah garpu karat-cpython, hadir dengan banyak perbaikan, tetapi hanya berfungsi dengan versi malam karat, jadi saya lebih suka menggunakan kandang untuk posting ini, bagaimanapun, contoh di sini harus bekerja juga dengan pyo3.
Pro: Sangat mudah untuk menulis fungsi karat dan impor dari Python dan seperti yang akan Anda lihat oleh tolok ukur yang layak dalam hal kinerja.
Cons: Distribusi proyek/lib/kerangka kerja Anda akan menuntut modul karat untuk dikompilasi pada sistem target karena variasi lingkungan dan arsitektur, akan ada tahap kompilasi yang tidak Anda miliki saat memasang perpustakaan python murni, Anda dapat membuatnya lebih mudah menggunakan rust-setuptool atau menggunakan milksnake untuk menyematkan data biner dalam roda Python.
Ya, Python dikenal sebagai "lambat" dalam beberapa kasus dan kabar baiknya adalah bahwa ini tidak masalah tergantung pada tujuan dan prioritas proyek Anda. Untuk sebagian besar proyek detail ini tidak akan terlalu penting.
Namun, Anda mungkin menghadapi case langka di mana satu fungsi atau modul mengambil terlalu banyak waktu dan terdeteksi sebagai hambatan kinerja proyek Anda, sering terjadi dengan penguraian string dan pemrosesan gambar.
Katakanlah Anda memiliki fungsi Python yang melakukan semacam pemrosesan string, ambil contoh mudah berikut dari counting pairs of repeated chars tetapi ada dalam pikiran bahwa contoh ini dapat direproduksi dengan fungsi string processing lainnya atau proses lain yang umumnya lambat di 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 cukup lambat untuk melakukan pemrosesan string besar sehingga Anda dapat menggunakan pytest-benchmark untuk membandingkan fungsi Pure Python (with Iterator Zipping) versus implementasi Regexp .
# Using a Python3.6 environment
$ pip3 install pytest pytest-benchmark
Kemudian tulis program Python baru yang disebut doubles.py
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 )Jalankan Pytest untuk membandingkan:
$ 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)
-----------------------------------------------------------------------------
Mari kita ambil Mean untuk perbandingan:
Peti adalah cara kami menyebut paket karat.
Memasang karat (cara yang disarankan adalah https://www.rustup.rs/) Rust juga tersedia di fedora dan rhel rust-toolset
Saya menggunakan
rustc 1.21.0
Di folder yang sama berjalan:
cargo new pyext-myrustlib Ini menciptakan proyek karat baru di folder yang sama yang disebut pyext-myrustlib yang berisi Cargo.toml (kargo adalah manajer paket karat) dan juga src/lib.rs (tempat kami menulis implementasi perpustakaan kami)
Itu akan menggunakan peti rust-cpython sebagai ketergantungan dan memberi tahu kargo untuk menghasilkan dylib untuk diimpor dari python
[ 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 " ]Apa yang perlu kita lakukan:
Impor semua makro dari cpython CRATE
Ambil Jenis Python dan PyResult dari Cpython ke dalam lingkup lib kami
Tulis implementasi fungsi count_doubles dalam Rust , perhatikan bahwa ini sangat mirip dengan versi python murni kecuali untuk:
Python sebagai argumen pertama, yang merupakan referensi ke juru bahasa Python dan memungkinkan karat menggunakan Python GIL&str val yang diketik sebagai referensiPyResult yang merupakan jenis yang memungkinkan peningkatan pengecualian PythonPyResult di Ok(total) ( Hasilnya adalah tipe enum yang mewakili keberhasilan (OK) atau kegagalan (err)) dan karena fungsi kami diharapkan untuk mengembalikan PyResult kompiler akan mengurus pembungkus Ok kami pada jenis itu. (Perhatikan bahwa Pyresult kami mengharapkan u64 sebagai nilai pengembalian) Menggunakan py_module_initializer! Makro Kami mendaftarkan atribut baru ke lib, termasuk __doc__ dan juga kami menambahkan atribut count_doubles yang merujuk pada Rust implementation of the function
try! makro yang setara dengan try.. exceptOk(()) - the () adalah tuple hasil kosong, setara dengan None dalam python # [ 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 ( ( ) )
} ) ;Sekarang mari kita bangun dalam kargo
$ 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 Sekarang mari kita salin .so lib yang dihasilkan ke folder yang sama di mana doubles.py kami adalah:
Catatan: Di Fedora Anda harus mendapatkan
.sodi sistem lain Anda mungkin mendapatkan.dylibdan Anda dapat mengganti nama itu mengubah ekstensi menjadi.so
$ cd ..
$ ls
doubles.py pyext-myrustlib/
$ cp pyext-myrustlib/target/release/libmyrustlib.so myrustlib.so
$ ls
doubles.py myrustlib.so pyext-myrustlib/Memiliki
myrustlib.sodi folder yang sama atau ditambahkan ke jalur Python Anda memungkinkannya untuk diimpor secara langsung, transparan karena itu adalah modul python.
Edit doubles.py Anda sekarang mengimpor versi Rust implemented kami dan juga menambahkan benchmark untuk itu.
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)
----------------------------------------------------------------------------- Mari kita ambil Mean untuk perbandingan:
Implementasi karat bisa 10x lebih cepat dari python regex dan 21x lebih cepat dari versi python murni.
Menarik bahwa versi regex hanya 2x lebih cepat dari python murni :)
Catatan: Bahwa angka itu hanya masuk akal untuk skenario khusus ini, untuk kasus lain yang perbandingannya mungkin berbeda.
Setelah artikel ini diterbitkan, saya mendapat beberapa komentar tentang R/Python dan juga di R/Rust
Kontribusi datang sebagai permintaan tarik dan Anda dapat mengirim yang baru jika Anda pikir fungsi dapat ditingkatkan.
Terima kasih kepada: Josh Stone, kami mendapat implementasi yang lebih baik untuk karat yang mengulangi string hanya sekali dan juga setara python.
Terima kasih kepada: Purple Pixie Kami mendapat implementasi Python menggunakan itertools , namun versi ini tidak berkinerja lebih baik, perlu perbaikan.
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 OK, itu bukan tujuan dari posting ini, posting ini tidak pernah tentang membandingkan Rust X other language , posting ini khusus tentang cara menggunakan karat untuk memperpanjang dan mempercepat python dan dengan melakukan itu berarti Anda memiliki alasan yang baik untuk memilih karat alih -alih other language atau dengan ekosistemnya atau dengan alasannya, dengan alasan ini atau hanya untuk mengikuti hype , atau sekadar karena Anda tidak seperti halnya.
Saya (secara pribadi) dapat mengatakan bahwa Rust lebih future proof karena baru dan ada banyak perbaikan yang akan datang, juga karena ekosistemnya, perkakas dan komunitas dan juga karena saya merasa nyaman dengan sintaks karat, saya sangat menyukainya!
Jadi, seperti yang diharapkan orang mulai mengeluh tentang penggunaan bahasa lain dan itu menjadi semacam tolok ukur, dan saya pikir itu keren!
Jadi sebagai bagian dari permintaan saya untuk perbaikan beberapa orang di Hacker News juga mengirim ide, Martinxyz mengirim implementasi menggunakan C dan Swig yang berkinerja sangat baik.
Kode C (swig boilerplate ommited)
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 ;
} Dan sesama Red Hatter Josh Stone meningkatkan implementasi karat lagi dengan mengganti chars dengan bytes sehingga merupakan kompetisi yang adil dengan C sebagai C membandingkan byte alih -alih unicode chars.
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 )
} Ada juga ide untuk membandingkan list comprehension python dan numpy jadi saya termasuk di sini
Numpy:
import numpy as np
def count_double_numpy ( val ):
ng = np . fromstring ( val , dtype = np . byte )
return np . sum ( ng [: - 1 ] == ng [ 1 :])Daftar pemahaman
def count_doubles_comprehension ( val ):
return sum ( 1 for c1 , c2 in zip ( val , val [ 1 :]) if c1 == c2 ) Kasing uji lengkap ada pada file test_all.py repositori.
-------------------------------------------------------------------------------------------------
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 2x lebih baik daripada yang lama membandingkan unicode charsRust masih lebih baik daripada C menggunakan SwigRust membandingkan unicode chars masih lebih baik dari numpyNumpy lebih baik dari first Rust implementation yang memiliki masalah iterasi ganda atas unicode charslist comprehension tidak membuat perbedaan yang signifikan daripada menggunakan pure PythonCatatan: Jika Anda ingin mengusulkan perubahan atau perbaikan, kirim PR di sini: https://github.com/rochacbruno/rust-python-example/
Saya menerima lebih banyak kontribusi karena permintaan tarikan salah satu dari itu adalah oleh Jason Knight untuk meningkatkan Rust menggunakan
RUSTFLAGS= " -C target-cpu=native " cargo build --release Dan bagi mereka yang ingin tahu tentang perbandingan dengan numba sehingga Shyba menerapkannya dan tersedia di cabang 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 totalLihat hasil baru dengan Numba di atas, cukup dekat dengan karat
----------------------------------------------------------------------------------------------------
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)
---------------------------------------------------------------------------------------------------- Dan ada juga implementasi Cython oleh Mike Fletcher di cabang cython https://github.com/rochacbruno/rust-python-example/tree/cython
dengan hasilnya:
----------------------------------------------------------------------------------------------------
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)
----------------------------------------------------------------------------------------------------Kembali ke tujuan dari posting ini bagaimana mempercepat ular python Anda dengan karat yang kami mulai dengan:
Dalam contoh ini karat dilakukan 100x lebih cepat dari ular surut kita.
Rust tidak akan secara ajaib menyelamatkan Anda, Anda harus tahu bahasa untuk dapat mengimplementasikan solusi pintar dan setelah diimplementasikan dengan benar, itu bernilai C dalam hal kinerja dan juga dilengkapi dengan bonus perkakas, ekosistem, komunitas, dan keselamatan yang luar biasa.
Rust mungkin belum menjadi general purpose language pilihan dengan tingkat kompleksitasnya dan mungkin belum menjadi pilihan yang lebih baik untuk menulis applications sederhana yang umum seperti situs web dan skrip test automation .
Namun, untuk specific parts dari proyek di mana Python dikenal sebagai hambatan dan pilihan alami Anda akan menerapkan ekstensi C/C++ , menulis ekstensi ini dalam karat tampaknya mudah dan lebih baik untuk dipertahankan.
Masih banyak perbaikan yang datang dalam karat dan banyak peti lainnya untuk menawarkan integrasi Python <--> Rust . Bahkan jika Anda tidak termasuk bahasa di sabuk alat Anda sekarang, ada baiknya untuk mengawasi mata untuk masa depan!
Contoh-contoh pada publikasi ini terinspirasi oleh Extending Python with Rust Talk oleh Samuel Cormier-Iijima di Pycon Canada . Video di sini: https://www.youtube.com/watch?v=-YLBUEZKG4M
Dan juga oleh My Python is a little Rust-y oleh Dan Callahan di Pycon Montreal . Video di sini: https://www.youtube.com/watch?v=3cwj0mh-4ma
Referensi Lainnya:
Bergabunglah dengan Komunitas:
Bergabunglah dengan Komunitas Rust, Anda dapat menemukan tautan grup di https://www.rust-lang.org/en-us/community.html
Jika Anda berbicara bahasa Portugis, saya sarankan untuk bergabung dengan https://t.me/rustlangbr dan ada juga http://bit.ly/canalrustbr di youtube.
Bruno Rocha
Info lebih lanjut: http://about.me/rochacbruno dan http://brunorocha.org