gpt4 book ai didi

python - 使用 rust-cpython 从 Rust 并行运行 Python 代码

转载 作者:行者123 更新时间:2023-12-03 11:30:14 29 4
gpt4 key购买 nike

我正在尝试使用 Rust 加速数据管道。管道包含一些我不想修改的 Python 代码,所以我尝试使用 rust-cpython 从 Rust 按原样运行它们。和多个线程。
但是,性能并不是我所期望的,它实际上与在单个线程中按顺序运行 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);
}

最佳答案

Python 的 CPython 实现不允许同时在多个线程中执行 Python 字节码。正如您自己注意到的那样,全局解释器锁 (GIL) 可以防止这种情况发生。

我们没有任何关于您的 Python 代码究竟在做什么的信息,因此我将给出一些一般性提示,您可以如何提高代码的性能。

  • 如果您的代码受 I/O 限制,例如从网络读取,您通常会从使用多个线程中获得很好的性能改进。阻塞 I/O 调用将在阻塞之前释放 GIL,因此其他线程可以在此期间执行。
  • 一些图书馆,例如NumPy,在不需要访问 Python 数据结构的长时间运行的库调用期间内部释放 GIL。使用这些库,即使您只使用该库编写纯 Python 代码,您也可以获得多线程、受 CPU 限制的代码的性能改进。
  • 如果您的代码受 CPU 限制并且大部分时间都在执行 Python 字节码,那么您通常可以使用多进程而不是线程来实现并行执行。 multiprocessing Python 标准库中的内容对此有所帮助。
  • 如果您的代码受 CPU 限制,大部分时间都在执行 Python 字节码,并且由于它访问共享数据而不能在并行进程中运行,那么您就不能在多个线程中并行运行它——GIL 可以防止这种情况。然而,即使没有 GIL,您也不能只在不更改任何语言的情况下并行运行顺序代码。由于您可以并发访问某些数据,因此您需要添加锁定并可能进行算法更改以防止数据竞争;如何执行此操作的详细信息取决于您的用例。 (如果你没有并发数据访问,你应该使用进程而不是线程——见上文。)

  • 除了并行性之外,使用 Rust 加速 Python 代码的一个好方法是分析您的 Python 代码,找到花费大部分时间的热点,并将这些位重写为您从 Python 代码调用的 Rust 函数。如果这不能给你足够的加速,你可以将这种方法与并行性结合起来——防止数据竞争在 Rust 中通常比在大多数其他语言中更容易实现。

    关于python - 使用 rust-cpython 从 Rust 并行运行 Python 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60148992/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com