Я пытаюсь ускорить конвейер данных, используя Rust. Конвейер содержит биты кода Python, которые я не хочу изменять, поэтому я пытаюсь запустить их как есть из Rust, используя rust- cpython и несколько потоков. Тем не менее, производительность не та, которую я ожидал, на самом деле это то же самое, что последовательный запуск python битов кода в одном потоке.
Читая документацию, я понимаю, что при вызове следующего вы на самом деле получаете указатель к одному Python интерпретатору, который может быть создан только один раз, даже если вы запускаете его из нескольких потоков отдельно.
let gil = Python::acquire_gil();
let py = gil.python();
Если это так, это означает, что Python GIL фактически предотвращает все параллельное выполнение в Rust. Есть ли способ решить эту проблему?
Вот код моего теста:
use cpython::Python;
use std::thread;
use std::sync::mpsc;
use std::time::Instant;
#[test]
fn python_test_parallel() {
let start = Instant::now();
let (tx_output, rx_output) = mpsc::channel();
let tx_output_1 = mpsc::Sender::clone(&tx_output);
thread::spawn(move || {
let gil = Python::acquire_gil();
let py = gil.python();
let start_thread = Instant::now();
py.run("j=0\nfor i in range(10000000): j=j+i;", None, None).unwrap();
println!("{:27} : {:6.1} ms", "Run time thread 1, parallel", (Instant::now() - start_thread).as_secs_f64() * 1000f64);
tx_output_1.send(()).unwrap();
});
let tx_output_2 = mpsc::Sender::clone(&tx_output);
thread::spawn(move || {
let gil = Python::acquire_gil();
let py = gil.python();
let start_thread = Instant::now();
py.run("j=0\nfor i in range(10000000): j=j+i;", None, None).unwrap();
println!("{:27} : {:6.1} ms", "Run time thread 2, parallel", (Instant::now() - start_thread).as_secs_f64() * 1000f64);
tx_output_2.send(()).unwrap();
});
// Receivers to ensure all threads run
let _output_1 = rx_output.recv().unwrap();
let _output_2 = rx_output.recv().unwrap();
println!("{:37} : {:6.1} ms", "Total time, parallel", (Instant::now() - start).as_secs_f64() * 1000f64);
}