DEV Community

Devang Tomar
Devang Tomar

Posted on • Originally published at devangtomar.hashnode.dev on

A Developer’s Dilemma: Navigating Rust πŸ¦€ and Python 🐍

Introduction

As developers, the choice of programming language is a compass guiding us through the vast landscapes of data analysis and machine learning. In this journey, two contenders have emerged as titans: Rust πŸ¦€ and Python 🐍. Join me as we explore the highs and lows of these languages from a developers perspective.

The Python Legacy 🐍

Python has long been the lingua franca of data science. Its simplicity and a myriad of libraries like NumPy, pandas, and scikit-learn have made it the default choice. Lets dive into a simple Python example:

# Python Code Example: Loading a CSV with pandas
import pandas as pd
data = pd.read_csv("dataset.csv")
print(data.head())

Enter fullscreen mode Exit fullscreen mode

The Rust Revolution πŸ¦€

Enter Rust, a systems programming language known for its performance and safety. While not traditionally associated with data science, its capabilities are intriguing.

Heres a taste of Rust:

// Rust Code Example: Reading a CSV with the csv crate
use std::error::Error;
use csv::ReaderBuilder;

fn main() -> Result<(), Box<dyn Error>> {
    let file = std::fs::File::open("dataset.csv")?;
    let mut rdr = ReaderBuilder::new().has_headers(true).from_reader(file);

    for result in rdr.records() {
        let record = result?;
        println!("{:?}", record);
    }

    Ok(())
}

Enter fullscreen mode Exit fullscreen mode

Performance Showdown πŸš€

One of Rusts key selling points is its performance. Lets compare the execution time of a simple data processing task in Python and Rust:

# Python Performance Test
import time

start_time = time.time()

# ... perform data processing ...

end_time = time.time()
print(f"Python Execution Time: {end_time - start_time} seconds")


// Rust Performance Test
use std::time::Instant;

fn main() {
    let start_time = Instant::now();

    // ... perform data processing ...

    let end_time = start_time.elapsed();
    println!("Rust Execution Time: {:?}", end_time);
}

Enter fullscreen mode Exit fullscreen mode

Ecosystem and Libraries πŸ“š

Pythons rich ecosystem is hard to match, with TensorFlow, PyTorch, and scikit-learn leading the charge. Rust, though, is catching up. The ndarray crate and the emerging tangram-rs for machine learning are making waves.

Safety and Concurrency πŸ›‘

Rusts ownership system ensures memory safety without sacrificing performance. Python, on the other hand, can sometimes struggle with concurrency. Lets explore a concurrent task in both languages.

# Python Concurrent Task
import concurrent.futures

def process_data(data_chunk):
    # ... perform data processing ...

with concurrent.futures.ThreadPoolExecutor() as executor:
    # ... submit tasks for parallel processing ...


// Rust Concurrent Task with Rayon
use rayon::prelude::*;

fn process_data(data_chunk: &mut Vec<i32>) {
    // ... perform data processing ...
}

fn main() {
    let mut data_chunks: Vec<Vec<i32>> = // ... prepare data chunks ...

    data_chunks.par_iter_mut().for_each(|chunk| {
        process_data(chunk);
    });
}

Enter fullscreen mode Exit fullscreen mode

Memory Management in Data Processing 🧠

In Python, memory management is abstracted away, making it easy for developers, data scientists to focus on algorithms. However, this can lead to challenges with large datasets. Rusts ownership system allows for fine-grained control over memory, ensuring efficient usage. Lets explore handling large arrays:

# Python Memory Management Example
import numpy as np

large_array = np.zeros(10**6, dtype=np.float64)
# ... perform operations on the array ...


// Rust Memory Management Example
fn main() {
    let mut large_array: Vec<f64> = vec![0.0; 1_000_000];
    // ... perform operations on the array ...
}

Enter fullscreen mode Exit fullscreen mode

Parallelism and Multithreading πŸš€

Pythons Global Interpreter Lock (GIL) can limit parallelism in CPU-bound tasks. Rust, with its emphasis on concurrency, allows for easy parallelization using libraries like Rayon.

# Python Multithreading Example
import concurrent.futures

def process_data(data_chunk):
    # ... perform data processing ...

with concurrent.futures.ThreadPoolExecutor() as executor:
    # ... submit tasks for parallel processing ...


// Rust Parallelism with Rayon
use rayon::prelude::*;

fn process_data(data_chunk: &mut Vec<i32>) {
    // ... perform data processing ...
}

fn main() {
    let mut data_chunks: Vec<Vec<i32>> = // ... prepare data chunks ...

    data_chunks.par_iter_mut().for_each(|chunk| {
        process_data(chunk);
    });
}

Enter fullscreen mode Exit fullscreen mode

Learning Curve and Accessibility πŸ“ˆ

Pythons readability and gentle learning curve have made it a go-to language for beginners. Rust, with its emphasis on ownership and borrowing, can be challenging initially but rewards with performance and memory safety.

Data Visualization Capabilities πŸ“Š

Pythons matplotlib and seaborn make data visualization a breeze. Rust, while not as feature-rich in this domain, offers libraries like Plotters for basic plotting.

# Python Data Visualization with Matplotlib
import matplotlib.pyplot as plt

data = [1, 2, 3, 4, 5]
plt.plot(data)
plt.show()


// Rust Data Visualization with Plotters
use plotters::prelude::*;

fn main() {
    let data = vec![1, 2, 3, 4, 5];

    let root = BitMapBackend::new("plot.png", (640, 480)).into_drawing_area();
    root.fill(&WHITE)?;

    let chart = ChartBuilder::on(&root)
        .build_cartesian_2d(0..data.len() as i32, 0..10)?;

    chart.draw_series(LineSeries::new(
        data.iter().enumerate().map(|(i, &v)| (i as i32, v)),
        &BLUE,
    ))?;
}

Enter fullscreen mode Exit fullscreen mode

Interoperability with Other Languages πŸ”„

Pythons ability to seamlessly integrate with C and C++ libraries through tools like Cython is advantageous. Rust, though relatively new to the scene, offers Foreign Function Interface (FFI) capabilities, allowing integration with C libraries.

# Python Interoperability with C
from ctypes import CDLL

my_lib = CDLL('./my_lib.so')
# ... use functions from the C library ...


// Rust Foreign Function Interface (FFI)
extern crate libc;

extern "C" {
    fn my_function();
}

fn main() {
    unsafe {
        my_function();
    }
}

Enter fullscreen mode Exit fullscreen mode

Choosing Your Adventure πŸ—Ί

In the realm of data science, the choice between Rust and Python is akin to selecting the right tool for a specific task. Pythons versatility and well-established ecosystem make it a reliable companion, while Rusts performance and safety make it a rising star.

The decision ultimately depends on the landscape you wish to navigate. Whether you choose the well-trodden paths of Python or embark on the uncharted territories of Rust, the journey is yours to craft. πŸš€πŸ‘©πŸ’»πŸ‘¨πŸ’»

Connect with Me on social media πŸ“²

🐦 Follow me on Twitter: devangtomar7

πŸ”— Connect with me on LinkedIn: devangtomar

πŸ“· Check out my Instagram: be_ayushmann

Checkout my blogs on Medium: Devang Tomar

# Checkout my blogs on Hashnode: devangtomar

πŸ§‘πŸ’» Checkout my blogs on Dev.to: devangtomar

Top comments (3)

Collapse
 
proteusiq profile image
Prayson Wilfred Daniel

The main reason I love Rust πŸ¦€ is the easy ability to call it in Python 🐍. I love Python.

When in need of computation speed, I have used C++ and Lua before to speed Python. Now I have dropped both C++ and Lua and going fully Rust as the work seamlessly with PyO3.

Collapse
 
devangtomar profile image
Devang Tomar

I'm glad you enjoyed the post! ❀️

Rust's seamless integration with PyO3 really enhances the Python development experience. Have you faced any specific challenges or found interesting use cases while working with Rust and Python together? πŸ€”

Collapse
 
proteusiq profile image
Prayson Wilfred Daniel

Not yet ☺️. Still on 🐍 + πŸ¦€ honeymoon