1. A função count_doubles conta o número de repetições de caracteres consecutivos em uma string.
2. A versão em Rust é 21x mais rápida do que a versão em Python usando zip.
3. Módulos em Rust podem ser criados e importados em Python para melhorar o desempenho de código Python.
Desenvolvimento web ágil com Python e web2py #qconsp #qcon
Escrevendo modulos python com rust
1. abCCdeFFghiJJklmnopqRRstuVVxyZZ... {milhões de caracteres aqui...}
1 2 3 4 5 6
Crie uma função que retorna a quantidade de repetições de caracteres em
sequência presentes em uma string.
def count_doubles(val):
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))
Pure Python Regexp
Qual é a mais rápida?
2. val = ''.join(random.choice(string.ascii_letters) for i in range(1_000_000))
def test_pure_python(benchmark):
benchmark(count_doubles, val)
def test_regex(benchmark):
benchmark(count_doubles_regex, val)
$ pip install pytest pytest-benchmark
$ pytest
--------------------------------------------------------------------------------- benchmark: 2 tests --------------------------------------------------------------------------------
Name (time in ms) Min Max Mean StdDev Median IQR Outliers OPS Rounds Iterations
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_regex 24.6824 (1.0) 32.3960 (1.0) 27.0167 (1.0) 1.8610 (1.0) 27.2148 (1.0) 2.9345 (4.55) 16;1 37.0141 (1.0) 36 1
test_pure_python 51.4964 (2.09) 62.5680 (1.93) 52.8334 (1.96) 2.3630 (1.27) 52.2846 (1.92) 0.6444 (1.0) 1;2 18.9274 (0.51) 20 1
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
● Regexp - 27.2148 ← versão regex é 2 x mais rápida
● Pure Python - 52.2846
Pode ficar mais rápido?
4. http://rust-lang.org
Rust é uma linguagem de programação de sistemas que roda incrivelmente
rápido, previne falhas de segmentação, e garante segurança entre threads.
● abstrações sem custo
● semântica de move
● segurança de memória garantida
● threads sem data races
● genéricos com traits
● pattern matching
● inferência de tipo
● sistema de execução mínimo
● bindings para C eficientes
5. Rust é uma linguagem que te permite construir abstrações
bem alto nível, mas sem abrir mão do controle em baixo
nível — isto é, o controle de como os dados são representados na memória, o controle de que modelo
de threading você quer usar, etc.
Rust é uma linguagem que em geral consegue detectar,
durante a compilação, os piores erros de paralelismo e
gerência de memória
(como acessar dados em threads diferentes sem sincronização, ou usar dados depois que foram
desalocados), mas te dá um escape hatch pra caso você saiba o que tá fazendo.
Rust é uma linguagem que, como não tem runtime, pode ser
usada pra se integrar a qualquer runtime;
você pode escrever uma extensão nativa em rust que seja chamada por um programa node.js, ou um
programa python, ou um programa em ruby. e, por outro lado, você pode scriptar um programa em rust
usando essas linguagens.
-- Elias Amaral (RustBR Telegram)
7. Macros! permite criar abstração de
sintaxe "açucar sintático".
A invocação de uma macro! é um "atalho"
para a chamada da versão expandida.
Esta expansão ocorre na pré compilação,
antes de qualquer chegagem estática.
11. $ cargo new pyext-myrustlib
$EDITOR Cargo.toml
[package]
name = "pyext-myrustlib"
[lib]
name = "myrustlib"
crate-type = ["dylib"]
[dependencies.cpython]
version = "0.1"
features = ["extension-module"]
Criando módulos "Python" com Rust!
Nome que será importável
do Python:
import myrustlib
Tipo de lib que será gerada
dylib, cdylib, staticlib...
Dependencia "cpython" que
será instalada e compilada
https://github.com/dgrunwald/rust-cpython
12. #[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(())
});
pyext-myrustlib/src/lib.rs
def count_doubles(val):
total = 0
for c1, c2 in zip(val, val[1:]):
if c1 == c2:
total += 1
return total
Equivalente em Python
13. $ cargo build --release
… compilando
$ cp target/release/libmyrustlib.so $PYTHONPATH/myrustlib.so
Copie com o mesmo nome que definiu no
"Cargo.toml" que será importável no Python.
"import myrustlib"
14. import myrustlib # <-- Import the Rust implemented module (myrustlib.so)
val = ''.join(random.choice(string.ascii_letters) for i in range(1_000_000))
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)
$ pip install pytest pytest-benchmark
● Rust - 2.5935 <-- Rust 21x mais rápido
● Regexp - 25.7664
● Python Zip - 53.6220
--------------------------------------------------------------------------------- benchmark: 3 tests ---------------------------------------------------------------------------------
Name (time in ms) Min Max Mean StdDev Median IQR Outliers OPS Rounds Iterations
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_rust 2.5555 (1.0) 2.9296 (1.0) 2.6085 (1.0) 0.0521 (1.0) 2.5935 (1.0) 0.0456 (1.0) 53;23 383.3661 (1.0) 382 1
test_regex 25.6049 (10.02) 27.2190 (9.29) 25.8876 (9.92) 0.3543 (6.80) 25.7664 (9.93) 0.3020 (6.63) 4;3 38.6285 (0.10) 40 1
test_pure_python 52.9428 (20.72) 56.3666 (19.24) 53.9732 (20.69) 0.9248 (17.75) 53.6220 (20.68) 1.4899 (32.70) 6;0 18.5277 (0.05) 20 1
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------