簡體   English   中英

使用 `pyo3` 從 Rust 到 Python 返回 `bytes` 的這 4 種方法有什么區別?

[英]What are the differences between these 4 methods of returning `bytes` from Rust to Python using `pyo3`?

我是 pyo3 的新手,也是pyo3的初學者。 我要做的是從 Rust slice返回到 Python bytes 我在pyo3文檔中閱讀了關於類型轉換memory 管理的內容,但我仍然感到有些失落。

這就是我現在所擁有的:

#[pyclass]
pub struct PyRust {}

#[pymethods]
impl PyRust {
    fn test_bytes_1(&self, py: Python) -> Py<PyAny> {
        let v = vec![1, 2, 3];
        let res: Py<PyAny> = v.as_slice().into_py(py);
        res
    }

    fn test_bytes_2(&self) -> Py<PyAny> {
        let v = vec![1, 2, 3];
        let res: Py<PyAny> = Python::with_gil(|py| v.as_slice().into_py(py));
        res
    }

    fn test_bytes_3(&self, py: Python) -> Py<PyBytes> {
        let v = vec![1, 2, 3];
        let res: Py<PyBytes> = PyBytes::new(py, v.as_slice()).into();
        res
    }

    fn test_bytes_4(&self) -> Py<PyBytes> {
        let v = vec![1, 2, 3];
        let res: Py<PyBytes> = Python::with_gil(|py| PyBytes::new(py, v.as_slice()).into());
        res
    }
}

我看到當從 Python 調用它們時,它們都返回了我的期望:

In [3]: x.test_bytes_1()
Out[3]: b'\x01\x02\x03'

In [4]: x.test_bytes_2()
Out[4]: b'\x01\x02\x03'

In [5]: x.test_bytes_3()
Out[5]: b'\x01\x02\x03'

In [6]: x.test_bytes_4()
Out[6]: b'\x01\x02\x03'

你能給我解釋一下有什么區別嗎? 什么是最好的方法? 他們有不同的成本嗎?

如果我使用%timeit我有這些:


In [4]: %timeit x.test_bytes_1()
2.05 µs ± 18.9 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

In [5]: %timeit x.test_bytes_2()
1.77 µs ± 7.85 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

In [6]: %timeit x.test_bytes_3()
1.97 µs ± 14.2 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

In [7]: %timeit x.test_bytes_4()
1.78 µs ± 14 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

所以似乎使用Python::with_gil更快,但為什么呢?

另外, Py<PyAny>如何以與Py<Bytes>相同的方式轉換回bytes PyAny是否有任何“記憶”它是從PyBytes創建的? 或者那里發生了不同的事情?

你能給我解釋一下有什么區別嗎?

查看代碼,似乎並沒有真正的區別,它們基本上通過稍微不同的路徑做同樣的事情,並且在很大程度上會相互委托,例如

v.as_slice().into_py(py)

應該這樣稱呼:

impl<'a> IntoPy<PyObject> for &'a [u8] {
    fn into_py(self, py: Python<'_>) -> PyObject {
        PyBytes::new(py, self).to_object(py)
    }
}

所以似乎使用 Python::with_gil 更快,但為什么呢?

可能是因為優化器可以更好地了解其操作,因此它能夠生成更高效的代碼:對於函數 1 和 3,gil 必須由 pyo3 的通用膠水代碼管理/獲取,因此編譯器無法洞察它(總體上它也可能是一個較慢的代碼路徑?)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM