自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

結(jié)合使用 Python 和 Rust

開(kāi)發(fā)
Rust 和 Python 的優(yōu)勢(shì)互補(bǔ)??梢允褂?Python 進(jìn)行原型設(shè)計(jì),然后將性能瓶頸轉(zhuǎn)移到 Rust 上。

Python 和 Rust 是非常不同的語(yǔ)言,但它們實(shí)際上非常搭配。但在討論如何將 Python 與 Rust 結(jié)合之前,我想先介紹一下 Rust 本身。你可能已經(jīng)聽(tīng)說(shuō)了這種語(yǔ)言,但可能還沒(méi)有了解過(guò)它的細(xì)節(jié)。

什么是 Rust?

Rust 是一種低級(jí)語(yǔ)言,這意味著程序員所處理的東西接近于計(jì)算機(jī)的 “真實(shí)” 運(yùn)行方式。

例如,整數(shù)類型由字節(jié)大小定義,與 CPU 支持的類型相對(duì)應(yīng)。雖然我們很想簡(jiǎn)單地說(shuō) Rust 中的 a+b 對(duì)應(yīng)于一條機(jī)器指令,但實(shí)際上并不完全是這樣!

Rust 編譯器鏈非常復(fù)雜。作為第一種近似的方法,將這樣的語(yǔ)句視為 “有點(diǎn)” 真實(shí)是有用的。

Rust 旨在實(shí)現(xiàn)零成本抽象,這意味著許多語(yǔ)言級(jí)別可用的抽象在運(yùn)行時(shí)環(huán)境中會(huì)被編譯去掉。

例如,除非明確要求,對(duì)象會(huì)在堆棧上分配。結(jié)果是,在 Rust 中創(chuàng)建本地對(duì)象沒(méi)有運(yùn)行時(shí)成本(盡管可能需要進(jìn)行初始化)。

最后,Rust 是一種內(nèi)存安全的語(yǔ)言。也有其他內(nèi)存安全的語(yǔ)言和其他支持零成本抽象的語(yǔ)言。但通常這些是兩類不同的語(yǔ)言。

內(nèi)存安全并不意味著不可能在 Rust 中出現(xiàn)內(nèi)存違規(guī)。它確實(shí)意味著只有兩種方式可能導(dǎo)致內(nèi)存違規(guī):

  • 編譯器的錯(cuò)誤。
  • 顯式聲明為不安全(unsafe)的代碼。

Rust 標(biāo)準(zhǔn)庫(kù)代碼有很多被標(biāo)記為不安全的代碼,雖然比許多人預(yù)期的少。這并不意味著該語(yǔ)句無(wú)意義。除了需要自己編寫不安全代碼的(罕見(jiàn)的)情況外,內(nèi)存違規(guī)通常是由基礎(chǔ)設(shè)施造成的。

為什么會(huì)有 Rust 出現(xiàn)?

為什么人們要?jiǎng)?chuàng)建 Rust?是哪些問(wèn)題沒(méi)有被現(xiàn)有編程語(yǔ)言解決嗎?

Rust 被設(shè)計(jì)成既能高效運(yùn)行,又保證內(nèi)存安全。在現(xiàn)代的聯(lián)網(wǎng)世界中,這是一個(gè)越來(lái)越重要的問(wèn)題。

Rust 的典型應(yīng)用場(chǎng)景是協(xié)議的低級(jí)解析。待解析的數(shù)據(jù)通常來(lái)自不受信任的來(lái)源,并且需要通過(guò)高效的方式進(jìn)行解析。

如果你認(rèn)為這聽(tīng)起來(lái)像 Web 瀏覽器所做的事情,那不是巧合。Rust 最初起源于 Mozilla 基金會(huì),它是為了改進(jìn) Firefox 瀏覽器而設(shè)計(jì)的。

如今,需要保證安全和速度的不僅僅是瀏覽器。即使是常見(jiàn)的微服務(wù)架構(gòu)也必須能夠快速解析不受信任的數(shù)據(jù),同時(shí)保證安全。

現(xiàn)實(shí)示例:統(tǒng)計(jì)字符

為了理解 “封裝 Rust” 的例子,需要解決一個(gè)問(wèn)題。這個(gè)問(wèn)題需要滿足以下要求:

  • 足夠容易解決。
  • 能夠?qū)懜咝阅苎h(huán)來(lái)優(yōu)化。
  • 有一定的現(xiàn)實(shí)意義。

這個(gè)玩具問(wèn)題的例子是判斷一個(gè)字符在一個(gè)字符串中是否出現(xiàn)超過(guò)了 X 次。這個(gè)問(wèn)題不容易通過(guò)高效的正則表達(dá)式解決。即使是專門的 Numpy 代碼也可能不夠快,因?yàn)橥ǔ](méi)有必要掃描整個(gè)字符串。

你可以想象一些 Python 庫(kù)和技巧的組合來(lái)解決這個(gè)問(wèn)題。然而,如果在低級(jí)別的語(yǔ)言中實(shí)現(xiàn)直接的算法,它會(huì)非???,并且更易于閱讀。

為了使問(wèn)題稍微有趣一些,以演示 Rust 的一些有趣部分,這個(gè)問(wèn)題增加了一些變化。該算法支持在換行符處重置計(jì)數(shù)(意即:字符是否在一行中出現(xiàn)了超過(guò) X 次?)或在空格處重置計(jì)數(shù)(意即:字符是否在單詞中出現(xiàn)了超過(guò) X 次?)。

這是唯一與 “現(xiàn)實(shí)性” 相關(guān)的部分。過(guò)多的現(xiàn)實(shí)性將使這個(gè)示例在教育上不再有用。

支持枚舉

Rust 支持使用枚舉(enum)。你可以使用枚舉做很多有趣的事情。

目前,只使用了一個(gè)簡(jiǎn)單的三選一的枚舉,并沒(méi)有其他的變形。這個(gè)枚舉編碼了哪種字符重置計(jì)數(shù)。

#[derive(Copy)]
enum Reset {
    NewlinesReset,
    SpacesReset,
    NoReset,
}

支持結(jié)構(gòu)

接下來(lái)的 Rust 組件更大一些:這是一個(gè)結(jié)構(gòu)(struct)。Rust 的結(jié)構(gòu)與 Python 的 dataclass 有些相似。同樣,你可以用結(jié)構(gòu)做更復(fù)雜的事情。

#[pyclass]
struct Counter {
    what: char,
    min_number: u64,
    reset: Reset, 
}

實(shí)現(xiàn)塊

你可以在 Rust 中使用一個(gè)單獨(dú)的塊,稱為實(shí)現(xiàn)(impl)塊,為結(jié)構(gòu)添加一個(gè)方法。但具體細(xì)節(jié)超出了本文的范圍。

在這個(gè)示例中,該方法調(diào)用了一個(gè)外部函數(shù)。這主要是為了分解代碼。更復(fù)雜的用例將指示 Rust 編譯器內(nèi)聯(lián)該函數(shù),以便在不產(chǎn)生任何運(yùn)行時(shí)成本的情況下提高可讀性。

#[pymethods]
impl Counter {
    #[new]
    fn new(what: char, min_number: u64, reset: Reset) -> Self {
        Counter{what: what, min_number: min_number, reset: reset}
    }
    fn has_count(
        &self,
        data: &str,
    ) -> bool {
        has_count(self, data.chars())
    }
}

函數(shù)

默認(rèn)情況下,Rust 變量是常量。由于當(dāng)前的計(jì)數(shù)(current_count)必須更改,因此它被聲明為可變變量。

fn has_count(cntr: &Counter, chars: std::str::Chars) -> bool {
    let mut current_count : u64 = 0;
    for c in chars {
        if got_count(cntr, c, &mut current_count) {
            return true;
        }
    }
    false
}

該循環(huán)遍歷字符并調(diào)用 got_count 函數(shù)。再次強(qiáng)調(diào),這是為了將代碼分解成幻燈片展示。它展示了如何向函數(shù)發(fā)送可變引用。

盡管 current_count 是可變的,但發(fā)送和接收站點(diǎn)都顯式標(biāo)記該引用為可變。這可以清楚地表明哪些函數(shù)可能修改一個(gè)值。

計(jì)數(shù)

got_count 函數(shù)重置計(jì)數(shù)器,將其遞增,然后檢查它。Rust 的冒號(hào)分隔的表達(dá)式序列評(píng)估最后一個(gè)表達(dá)式的結(jié)果,即是否達(dá)到了指定的閾值。

fn got_count(cntr: &Counter, c: char, current_count: &mut u64) -> bool {
    maybe_reset(cntr, c, current_count);
    maybe_incr(cntr, c, current_count);
    *current_count >= cntr.min_number
}

重置代碼

reset 的代碼展示了 Rust 中另一個(gè)有用的功能:模式匹配。對(duì) Rust 中匹配的完整描述需要一個(gè)學(xué)期級(jí)別的課程,不適合在一個(gè)無(wú)關(guān)的演講中講解。這個(gè)示例匹配了該元組的兩個(gè)選項(xiàng)之一。

fn maybe_reset(cntr: &Counter, c: char, current_count: &mut u64) -> () {
    match (c, cntr.reset) {
        ('\n', Reset::NewlinesReset) | (' ', Reset::SpacesReset)=> {
            *current_count = 0;
        }
        _ => {}
    };
}

增量支持

增量將字符與所需字符進(jìn)行比較,并在匹配時(shí)增加計(jì)數(shù)。

fn maybe_incr(cntr: &Counter, c: char, current_count: &mut u64) -> (){
    if c == cntr.what {
        *current_count += 1;
    };
}

請(qǐng)注意,我在本文中優(yōu)化了代碼以適合幻燈片。這不一定是 Rust 代碼的最佳實(shí)踐示例,也不是如何設(shè)計(jì)良好的 API 的示例。

為 Python 封裝 Rust 代碼

為了將 Rust 代碼封裝到 Python 中,你可以使用 PyO3。PyO3 Rust “crate”(即庫(kù))允許內(nèi)聯(lián)提示將 Rust 代碼包裝為 Python,使得修改兩者更容易。

包含 PyO3 crate 原語(yǔ)

首先,你必須包含 PyO3 crate 原語(yǔ)。

use pyo3::prelude::*;

封裝枚舉

枚舉需要被封裝。derive 從句對(duì)于將枚舉封裝為 PyO3 是必需的,因?yàn)樗鼈冊(cè)试S類被復(fù)制和克隆,使它們更容易在 Python 中使用。

#[pyclass]
#[derive(Clone)]
#[derive(Copy)]
enum Reset {
    /* ... */
}

封裝結(jié)構(gòu)

結(jié)構(gòu)同樣需要被封裝。在 Rust 中,這些被稱為 “宏”,它們會(huì)生成所需的接口位。

#[pyclass]
struct Counter {
    /* ... */
}

封裝實(shí)現(xiàn)

封裝實(shí)現(xiàn)(impl)更有趣。增加了另一個(gè)名為 new 的宏。此方法被標(biāo)記為 #[new],讓 PyO3 知道如何為內(nèi)置對(duì)象公開(kāi)構(gòu)造函數(shù)。

#[pymethods]
impl Counter {
    #[new]
    fn new(what: char, min_number: u64,
          reset: Reset) -> Self {
        Counter{what: what,
          min_number: min_number, reset: reset}
    }
    /* ... */
}

定義模塊

最后,定義一個(gè)初始化模塊的函數(shù)。此函數(shù)具有特定的簽名,必須與模塊同名,并用 #[pymodule] 修飾。

#[pymodule]
fn counter(_py: Python, m: &PyModule
) -> PyResult<()> {
    m.add_class::<Counter>()?;
    m.add_class::<Reset>()?;
    Ok(())
}

? 顯示此函數(shù)可能失敗(例如,如果類沒(méi)有正確配置)。 PyResult 在導(dǎo)入時(shí)轉(zhuǎn)換為 Python 異常。

Maturin 開(kāi)發(fā)

為了快速檢查,用 maturin develop 構(gòu)建并將庫(kù)安裝到當(dāng)前虛擬環(huán)境中。這有助于快速迭代。

$ maturin develop

Maturin 構(gòu)建

maturin build 命令構(gòu)建一個(gè) manylinux 輪子,它可以上傳到 PyPI。輪子是特定于 CPU 架構(gòu)的。

Python 庫(kù)

從 Python 中使用庫(kù)是最簡(jiǎn)單的部分。沒(méi)有任何東西表明這與在 Python 中編寫代碼有什么區(qū)別。這其中的一個(gè)有用方面是,如果你優(yōu)化了已經(jīng)有單元測(cè)試的 Python 中的現(xiàn)有庫(kù),你可以使用 Python 單元測(cè)試來(lái)測(cè)試 Rust 庫(kù)。

導(dǎo)入

無(wú)論你是使用 maturin develop 還是 pip install 來(lái)安裝它,導(dǎo)入庫(kù)都是使用 import 完成的。

import counter

構(gòu)造函數(shù)

構(gòu)造函數(shù)的定義正好使對(duì)象可以從 Python 構(gòu)建。這并不總是如此。有時(shí)僅從更復(fù)雜的函數(shù)返回對(duì)象。

cntr = counter.Counter(
    'c',
    3,
    counter.Reset.NewlinesReset,
)

調(diào)用函數(shù)

最終的收益終于來(lái)了。檢查這個(gè)字符串是否至少有三個(gè) “c” 字符:

>>> cntr.has_count("hello-c-c-c-goodbye")
True

添加一個(gè)換行符會(huì)觸發(fā)剩余操作,這里沒(méi)有插入換行符的三個(gè) “c” 字符:

>>> cntr.has_count("hello-c-c-\nc-goodbye")
False

使用 Rust 和 Python 很容易

我的目標(biāo)是讓你相信將 Rust 和 Python 結(jié)合起來(lái)很簡(jiǎn)單。我編寫了一些“粘合劑”代碼。Rust 和 Python 具有互補(bǔ)的優(yōu)點(diǎn)和缺點(diǎn)。

Rust 非常適合高性能、安全的代碼。Rust 具有陡峭的學(xué)習(xí)曲線,對(duì)于快速原型解決方案而言可能有些笨拙。

Python 很容易入手,并支持非常緊密的迭代循環(huán)。Python 確實(shí)有一個(gè)“速度上限”。超過(guò)一定程度后,從 Python 中獲得更好的性能就更難了。

將它們結(jié)合起來(lái)完美無(wú)縫。在 Python 中進(jìn)行原型設(shè)計(jì),并將性能瓶頸移至 Rust 中。

使用 Maturin,你的開(kāi)發(fā)和部署流程更容易進(jìn)行。開(kāi)發(fā)、構(gòu)建并享受這一組合吧!

責(zé)任編輯:龐桂玉 來(lái)源: Linux中國(guó)
相關(guān)推薦

2020-10-21 14:54:02

RustGolang開(kāi)發(fā)

2012-04-19 10:04:20

ibmdw

2023-05-04 07:33:39

Rust變量常量

2024-09-13 09:55:38

RustP2P網(wǎng)

2009-07-31 16:28:26

ibmdwJavaJSP

2013-03-18 11:05:26

HadoopCouchbase

2022-08-05 07:43:40

IoNT區(qū)塊鏈中心化

2021-02-24 07:42:34

PythonRust語(yǔ)言

2024-08-07 09:33:58

2023-06-15 17:00:11

Rust循環(huán)

2011-12-15 01:01:16

ibmdw

2011-07-08 17:49:38

WITH ASCTE

2015-04-20 10:06:37

PHP Rust 創(chuàng)建PHP 擴(kuò)展

2023-05-23 18:11:12

Rust數(shù)組元組

2020-07-15 08:00:52

Rust語(yǔ)言技巧

2018-01-27 21:19:06

前端Rust Service

2024-03-01 07:26:49

RustPolars機(jī)器學(xué)習(xí)

2022-04-14 09:19:34

Notion開(kāi)源AppFlowy

2024-02-26 07:26:27

RustC++開(kāi)發(fā)

2024-09-06 11:34:15

RustAI語(yǔ)言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)