Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Cuándo usar extensiones nativas en Rust: Rendimiento accesible y seguro

Cuándo usar extensiones nativas en Rust: Rendimiento accesible y seguro

Eric Arellano

April 28, 2021
Tweet

Other Decks in Technology

Transcript

  1. Cuándo usar extensiones nativas en Rust: Rendimiento accesible y seguro

    Eric Arellano @EArellanoAZ PyCon US, Mayo 2021
  2. Plan de presentación 1. ¿Cuándo usar las extensiones nativas? 2.

    ¿Por qué usar Rust? 3. ¿Qué sigue de esto?
  3. Quién soy • Ingeniero para Toolchain Labs, Twitter, y Foursquare

    • Colaborador del proyecto Pants por 3 años • Consejero para jóvenes LGBTQ en crisis • Amante de cerdos
  4. Pants Una herramienta que coordina los builds. • ejecutar pruebas

    • empaqueter distribuciones • ejecutar linters • formatear código • generar Protobufs
  5. Pants - como usamos Rust + Python Python 3 para

    modelar toda la lógica de un build. Rust para la gestión de tareas, "the engine": • Lanzar procesos con concurrencia • Escribir/leer al caché • Observar el sistema de archivos para cambios
  6. ¿Por qué CPython puede ser lento? Según "Why is Python

    Slow" (Anthony Shaw): • Compilación ◦ Hay una etapa de interpretación ◦ Bytecode no está siempre optimizado • Recolector de basura • Limites a la concurrencia ◦ GIL (global interpreter lock)
  7. Perfilar Característica de rendimiento Herramientas antes y después; CPU vs.

    I/O hyperfine, GNU time "hot spots" PySpy, "flame graphs" como Snakeviz gasto de memoria Guppy3
  8. Perfiles del GIL Es complicado porque hay que identificar la

    duración de espera. Tutorial en YouTube: "Identifying Contention on the Python GIL in Rust from macOS" por Pants Build, https://youtu.be/zALr3zFIQJo
  9. Algunas opciones cuando hay un problema de rendimiento 1. Optimizar.

    2. Probar la concurrencia de Python. 3. Probar PyPy o Numba. 4. Reescribir todo en otro lenguaje. 5. Usar las extensiones nativas.
  10. Opción 1: optimizar Por ejemplo: • Cambiar las estructuras de

    datos y algoritmos • Usar __slots__ para menos gasto de memoria Es bueno, pero hay limites fundamentales, como el GIL.
  11. Opción 2: la concurrencia de Python • multiprocessing ◦ evita

    el GIL, pero hay gastos • threading ◦ todavía tiene el GIL ◦ es útil cuando I/O-bound, no tanto cuando CPU-bound • asyncio http://masnun.rocks/2016/10/06/async-python-the-different-forms-of-concurrency/
  12. PyPy y Numba "If you want your code to run

    faster, you should probably just use PyPy." Guido van Rossum, creador de Python
  13. Opción 4: reescribir todo en otro lenguaje "The single worst

    strategic mistake that any software company can make: rewrite the code from scratch." Joel Spolsky, 2000 "Things You Should Never Do, Part 1"
  14. Opción 5: las extensiones nativas • Una mezcla de Python

    y otro lenguaje • FFI (Foreign Function Interface) • Importado como un módulo típico a través de un archivo .so
  15. Extensión - demo def suma_dos(x: int) -> int: return x

    + 2 if __name__ == "__main__": assert suma_dos(2) == 4 proyecto └── demo.py
  16. Extensión - demo from mi_extension_nativa import suma_dos if __name__ ==

    "__main__": assert suma_dos(2) == 4 proyecto ├── demo.py └── mi_extension_nativa.so
  17. Cuándo las extensiones nativas pueden valer la pena • Optimizaciones

    y PyPy/Numpy no están suficientes • Hay "hot spots" mucho más rápidos con un lenguaje nativo ◦ Escribir experimentos sencillos para probar
  18. Por que Pants escogió una extensión nativa • Después de

    las optimizaciones, todavía gastaba 80% del tiempo en la gestión de tareas • Queriamos usar asyncio, pero con más control y sin el GIL • Tenemos estructuras de datos enormes -> control de la memoria
  19. Las extensiones nativas llevan complejidad • dos lenguajes para entender

    y mantener • empaquetamiento Menos riesgo con un límite claro de su interfaz.
  20. Algunas opciones para extensiones nativas • C ◦ ctypes/cffi ◦

    CPython API ◦ Cython* • C++ ◦ pybind11 • Rust ◦ Rust-CPython ◦ PyO3 • Golang *Cython es un dialecto de Python
  21. Rust - demo fn suma_dos(x: i64) -> i64 { x

    + 2 } fn main() { println!("{}", suma_dos(2)); }
  22. Extensión - demo use pyo3::prelude::*; use pyo3::wrap_pyfunction; #[pyfunction] fn suma_two(x:

    i64) -> PyResult<i64> { Ok(x + 2) } #[pymodule] fn mi_extension_nativa(py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(suma_dos, m)?)?; Ok(()) }
  23. ¡Rust puede usar Python también! use pyo3::prelude::*; fn main() {

    Python::with_gil(|py| { let sys_module = py.import("sys").unwrap(); let version: String = sys_module .get("version") .unwrap() .extract() .unwrap(); println!("Usando Python {}", version); } }
  24. C y C++ no tienen la seguridad de memoria. La

    habilidad no elimina el riesgo.
  25. • ~70% de vulnerabilidades de Microsoft 1 • ~70% de

    vulnerabilidades severos de Android 2 • 74% de vulnerabilidades de Firefox Style Component 3 1. https://msrc-blog.microsoft.com/2019/07/18/we-need-a-safer-systems-programming-language/ 2. https://security.googleblog.com/2021/04/rust-in-android-platform.html 3. https://hacks.mozilla.org/2019/02/rewriting-a-browser-component-in-rust/ Vulnerabilidades de memoria son comunes
  26. error[E0382]: borrow of moved value: `s1` --> src/main.rs:5:28 | 2

    | let s1 = String::from("hello"); | -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait 3 | let s2 = s1; | -- value moved here 4 | 5 | println!("{}, world!", s1); | ^^ value borrowed here after move Rust - seguridad de memoria sin un recolector de basura El compilador checa la seguridad de memoria a través de su "borrow checker".
  27. Rust - concurrencia sin miedo El compilador checa la seguridad

    de concurrencia—incluyendo carreras de datos—a través de su "borrow checker". error[E0373]: closure may outlive the current function, but it borrows `v`, which is owned by the current function --> src/main.rs:6:32 | 6 | let handle = thread::spawn(|| { | ^^ may outlive borrowed value `v` 7 | println!("Aquí hay un vector: {:?}", v); | - `v` is borrowed here
  28. Rust - otras ventajas • Sistema de tipo moderno, ~MyPy

    • Herramientas modernas • Buena documentación y mensajes de errores • Una comunidad inclusiva
  29. Rust - algunas desventajas • Más complejo que Python •

    Compilación lento • Todavía joven - no siempre hay bibliotecas maduras
  30. Recursos sobre Rust "The Rust Book" • Gratis • Es

    official • Hay una traducción, github.com/ManRR/rust-book-es doc.rust-lang.org/stable/book
  31. Resumen 1. El rendimiento no siempre importa mucho. 2. Perfilen.

    Intenten optimizar, prueben PyPy/Numba, y tal vez antes la concurrencia de Python. 3. Las extensiones nativas en Rust ofrecen rendimiento seguro y accesible. Rust + Python están listos para la producción.
  32. Sigan la conversación con el equipo Pants Twitter: @pantsbuild @EArellanoAZ

    Slack: pantsbuild.org para el enlace Pycon 2021 Startup Row: