Rust 和Erlang的對比

來源:互聯網
上載者:User

Rust 和Erlang的對比

在我為期兩年的電信網路模擬器的程式員生涯中,我將Erlang的並發性、容錯性和分散式運算等特性充分利用到了許多CPU密集型應用程式上。 

Erlang是一種進階的、動態、函數式的語言,它提供了輕量級的流程、不變性、位置透明的分布式、訊息傳遞、監督行為等。不幸的是,它在底層的工作中並不是最理想的,而且顯然那也不是它們的主要意圖。例如,最典型的用例之一就是XML解析,Erlang並不擅長。事實上,XML節必須從命令列或網路中讀取,而處理來自Erlang虛擬機器之外的任何東西都是繁瑣的工作。你可能也瞭解這個問題。對於這種情況,不妨考慮一下採用不同的語言。特別是,Rust最近由於其混合特性集而走到了前台,它對Erlang的許多方面都有類似的承諾,並且在底級效能和安全性方面增加了額外的好處。 

Rust編譯成二進位,並在硬體上直接運行,就像你的C/ c++程式一樣。它和C/ c++有什麼不同? 很多。它的座右銘是這麼說的:“Rust是一款運行速度非常快、可以防止段錯誤,並確保安全執行緒的系統程式設計語言”。

本文將重點討論Erlang和Rust之間的比較,強調它們的相似和不同,研究Rust 的Erlang開發人員和研究Erlang的Rust 開發人員可能都會對它感興趣。最後一節將詳細介紹每種語言能力和缺點。

不變性

Erlang: 變數在Erlang中是不可變的,一旦綁定不能被改變,也不能被重新綁定為不同的值。 

Rust: Rust中的變數預設情況下也是不可變的,但是通過向它們添加mut關鍵字可以很容易地使其變為可變的。Rust還引入了所有權和借出的概念,以有效地管理記憶體配置。例如,字串文字儲存在可執行檔中,字串在分配給其他變數時會轉移,而像integer(i32,i64,u32…), float(f32,f64)等未經處理資料類型直接儲存在堆棧中。

模式比對

Erlang: Erlang代碼簡潔性的優點在於它的模式比對功能,在任何地方都可以使用case語句以及”=”(等號),包括函數名、參數數量和參數本身。

Rust: 在let綁定中,=符號可以用於綁定,也可以用於模式比對。除此之外,Rust match類似於Erlang中的case語句和大多數其他語言中的switch語句,它嘗試在多個case中進行模式比對,然後分支到匹配到的那個。功能/方法重載不是Rust內建的,但它可以使用特徵(trait)。確鑿(Irrefutable )的模式比對任何事物,它們一直都會有效。例如: 在let x=5中,x總是與值5綁定。相反,不確鑿(refutable )的模式在某些情況下可能會匹配不到。例如:在if let Some(x) = somevalue 中明確地說somevalue應該處理任何除了None之外的值。 確鑿的模式可以直接在一個let綁定中使用,而不確鑿的模式可以在if let、while let或者 match 結構體中使用。 

迴圈

Erlang: 在Erlang中可以使用遞迴或列表推導完成迴圈。 

Rust: 在命令式語言中,迴圈會以如for、while和loop等常見方式出現,並帶有基本的迴圈結構。除此之外,還有迭代器。

閉包和匿名函數

Erlang: Erlang有匿名函數,可以通過用fun和end關鍵字將代碼塊框起來聲明。所有匿名函數都是使用當前上下文閉包,而且以在相同節點或其他串連節點上跨進程傳遞。匿名函數為Erlang分布式機制增加了極大的價值。 

Rust: Rust也支援使用匿名函數的閉包。這些還可以“捕獲”環境,並可以在其他地方執行(在不同的方法或線程上下文中)。匿名函數可以儲存在一個變數中,可以作為函數和跨線程的參數傳遞。

列表和元組

Erlang: 列表是動態單向鏈表,可以將任何Erlang資料類型儲存為元素。列表中的元素不能通過索引獲得,而必須從頭開始遍曆(不像Rust中的數組)。元組是固定大小的,在運行時不能改變。它們可以是模式比對的。 

Rust: 與Erlang中的列表類似,Rust有向量(vector)和數組。數組是固定大小的,如果在編譯時間元素的大小是已知的,就可以使用它。向量是內部鏈表(類似於Erlang中的列表)。當大小動態變化時使用向量,可以是普通的,也可以是雙端的。普通向量是單向的,而雙端向量是雙向鏈表,可以在兩端同時增長。Rust也有在運行時不能改變的元組。如果函數需要返回多個值,則可以使用元組。元組也可以是模式比對的。

迭代器

Erlang: Erlang中的迭代器是與列表一起使用的。列表模組提供了各種各樣的迭代機制,如map、filter、zip、drop等。除此之外,Erlang還支援列表推導,它使用產生器作為列表,並且可以根據謂詞對列表中的每個元素執行操作。結果是另一個列表。 

Rust: 向量、雙端向量和數組可以由迭代器來使用。在Rust中迭代器預設是懶惰的。除非在末尾有收集器,否則源不會被消耗。與傳統的迴圈約束(如迴圈等)相比,迭代器提供了一種更自然的方式來使用任何列表資料類型,因為它們從來不會超出範圍。

Record和Map

Erlang: Record是在編譯時間定義的固定大小的結構,而Map是動態,它們的結構可以在運行時聲明或修改。Map類似於其他語言中的hashmap,它們被用作KVStore for Redis。

Rust: Rust支援在編譯時間聲明結構體。結構體不能在運行時修改,例如,不能添加或刪除成員。由於Rust是一種低級語言,所以結構體可以儲存引用。引用需要使用生命週期參數來防止懸Null 參考。Rust有一個標準的集合庫,它支援許多其他的資料結構,比如Map、Set、序列等等。所有這些資料結構也可以惰性迭代。

String、Binary和Bitstring

Erlang: Erlang中的字串只是在單向鏈表中儲存每個字元的ASCII值的列表。因此,在字串的開頭追加字元總是比在它的末尾要容易。在Erlang中Binary很特殊,它們就像一個連續的位元組數組,構成位元組(8位序列)。Bitstring(位串)是Binary的特殊情況,它儲存不同大小的位序列,例如三個1位序列、一個4位序列等。位串的長度不必是8的倍數。String、Binary和Bitstring支援更進階別的便利文法,使模式比對更容易。因此,如果您進行中網路編程,那麼打包和解包一個網路通訊協定包是很簡單的。 

Rust: 在Rust中,有兩類字串。字串字面值既不是儲存在堆上,也不是儲存在堆棧上,而是直接儲存在可執行檔中。字串字面值是不可變的。字串可以有動態大小。在這種情況下,它們儲存在堆上,而其引用儲存在堆棧上。如果在編譯時間字串是已知的,則它們以文字形式儲存,而在編譯時間未知的字串則儲存在堆中。這是一種有效方法,可以在編譯時間識別記憶體配置策略,並在運行時應用它。

生命週期

Erlang: 變數只綁定在函數的範圍內,並由特定於當前進程的垃圾收集器釋放。因此, 每個變數的生命週期與使用它的函數相同。也就是說,程式應該儘可能地模組化到函數中, 以便有效地使用記憶體。此外, 您甚至可以使用特殊的觸發器來觸發記憶體回收,在需要時調用Erlang: gc ()觸發記憶體回收. 

Rust: Rust沒有記憶體回收Rust 使用生命週期來管理記憶體。一個範圍內的每個變數(用花括弧或函數的主體進行分隔)都被賦予一個新的生命週期,如果它不是從父進程中借出或引用的話。變數的生命週期不會在該變數被借用的範圍結束時結束,它只在父範圍的末尾結束。因此,每個變數的生命週期要麼由當前範圍管理,要麼由父範圍管理,由編譯器來確保這一點。在編譯過程中,Rust暗自注入代碼,以便當該變數的��命周期結束時,除去與變數相關的值。這種方法可以避免使用垃圾收集來確定哪些變數可以被釋放。通過在函數內管理生命週期,Rust提供了對記憶體的細粒度控制。與Erlang函數在功能結束時觸發垃圾收集的功能不同,在Rust中,您可以使用{}將您的代碼劃分為多個範圍,而編譯器將在每個範圍的末尾放置drop代碼。 

變數綁定、所有權和借出

Erlang: Erlang有一個簡單的綁定方式。如果一個變數之前是未綁定的,那麼任何一個變數的出現都會被綁定到右邊的值,否則它就是模式比對的。Erlang中的任何類型都可以綁定到一個變數。變數只綁定在它們出現的函數上下文中,並且在不再使用時由特定於當前進程的垃圾收集器釋放。資料的所有權不能轉移給不同的變數。如果同一個函數上下文中的另一個變數想要擁有相同的資料,那麼它必須複製這個資料。這符合Erlang的不共用任何東西的理念,並使使用複製值安全地發送到不同的節點或進程而不進行資料競爭。在 Erlang 中, 沒有引用, 因此也沒有借用。所有資料都被分配到堆上。 

Rust: 所有權和借出是Rust中兩個強大的概念,使該語言在主流語言中獨樹一幟。這也正是為什麼Rust被認為是低層次無資料競爭語言的非常重要的原因,這可以在不需要垃圾收集器的情況下提供記憶體安全,從而保證了最小的運行時開銷。資料的所有權屬於一個變數,這意味著沒有其他變數可以共用該資料的所有權。如果需要的話,所有權被轉移到一個不同的變數賦值上,舊變數不再有效。如果將變數作為參數發送給函數,則所有權也會被轉移。這種操作稱為move,因為資料的所有權被轉移了。所有權有助於有效地管理記憶體。 

所有權規則:每個值在某一時刻會有一個明確的所有者:如果所有者超出範圍,則該值會被垃圾收集。

當一個值的所有權被臨時從擁有它的變數中借用到一個函數或一個變數時,就會發生借出了,要麼是可變的,要麼是不可變的。一旦借用超出了功能或{}分隔塊的範圍,所有權就會返回。在借用期間,父函數/範圍對變數沒有所有權,直到被借用的函數/範圍結束為止。 

借出規則:對於一個變數,可以有任意數量的不可變引用,但是在一個範圍內只能有一個不可變的引用。此外,可變和不可變引用不能在一個範圍內共存。

引用計數

引用計數用於跟蹤其他進程/線程對變數的使用。一個新進程/線程持有該變數時引用計數將增加,當一個進程/線程退出時引用計數將遞減。當計數達到0時,值被刪除。

Erlang: 當資料在Erlang中跨多個進程傳遞時,資料通過一條訊息傳遞。這意味著它是被複製到其他進程的堆中的,而不是引用計數。在一個進程內複製的資料由每進程(per-process)記憶體回收行程在其生命週期末尾進行記憶體回收。然而,超過64KB大小的binary跨Erlang進程傳遞時會被引用計數。 

Rust: 當資料線上程間共用時,資料不會被複製以提高效率。而是由一個引用計數器封裝。引用有些特殊,因為多個可變引用可以傳遞給多個線程,但同時要對資料同步進行互斥。不可變資料的引用不需要互斥。 所有相關的檢查都是在編譯時間完成的,並有助於防止Rust中的資料競爭。

訊息傳遞

Erlang: Erlang中的訊息傳遞是非同步。假設一個進程向另一個進程發送訊息,如果該鎖立即可用,則訊息會被複製到另一個進程信箱;否則它將被複製到一個堆片段,正在接收的進程將在稍後的時間點得到它。這可以實現真正的非同步和資料無競爭行為,儘管代價是在另一個進程的堆中複製相同的訊息。 

Rust: Rust有通道,就像水在兩點之間流動一樣。如果在一條小溪上放個東西,它就會流向另一端。每當建立一個Rust通道,就會隨之建立一個發射和一個接收處理器。發射處理器用於把訊息放到通道上,而接收處理器閱讀這些訊息。一旦發射器把一個值放到了通道上,那麼這個值的所有權就轉移給了那個通道,如果有其他的線程從這條通道讀取這個值,那麼其所有權就轉移給了這個線程。當使用通道時,所有權的原則仍然保留,每個值都只有一個所有者。在最後一個線程退出時,資源被記憶體回收。

共用的突變

Erlang: 在Erlang中共用是一種罪,但是Erlang允許使用Erlang Term Storage(ETS)進行控制突變。ETS表可以跨多個表共用,並在內部同步,以防止競爭。ETS可以調優,以帶來高的讀並發性或高的寫並發性。整個表可以附加到一組進程中,如果所有這些進程退出,整個表將被記憶體回收。 

Rust: 作為一種低級語言,Rust提供了一種資源共用突變的方式。結合引用計數與互斥量,資源訪問與多個線程的突變同步。如果共用相同資源的多個線程退出,資源將被最後一個退出線程記憶體回收。這提供了一種乾淨、高效的共用、變異和清理資源的方式。

行為

Erlang: 行為是共同模式的形式化。其思想是將一個過程的代碼劃分為一個通用的部分(行為模組)和一個特定的部分(一個回調模組)。您只需要實現一些回調,並調用特定的API來使用行為。有各種標準的行為,如genserver、genfsm、gensupervisor等。例如,如果您想要一個獨立的進程,可以像伺服器一樣持續運行,偵聽非同步和同步調用或訊息,那麼您就可以實現它的genserver行為。它還可以實現自訂行為。

Rust: 如果你有一組在多種資料類型中通用的方法,它們可以被聲明為一個特徵(trait)。特徵是Rust版的介面,它們是可擴充的。Traits消除了對傳統方法重載的需求,並提供了一種操作符重載的簡單模式。 

記憶體配置

Erlang: 變數在Erlang中是動態強型別的。在運行時不提供類型定義,並且在運行時最小化類型轉換以防止類型錯誤。當程式運行時,變數會在底層OS線程的堆上動態分配,並在記憶體回收時釋放。 

Rust: Rust是一種靜態,嚴格的和推斷的語言。靜態意味著Rust編譯器會在編譯期間檢查類型以防止運行時發生類型錯誤。有些類型是在編譯過程中推斷出來的,比如:最初聲明為String類型的字串變數被分配給不同的變數,不需要隱式地宣告類型,新變數的資料類型將由編譯器本身推斷出來。編譯器努力確定哪些變數可以分配到堆棧上,哪些變數可以分配到堆上,因此Rust記憶體配置非常高效和快速。與Erlang不同的是,在很大程度上,Rust使用堆棧分配所有在編譯時間已知大小的資料類型,而動態資料類型(如Strings,Vectors等)則在運行時在堆上分配。

可擴充性、容錯性、分布式

Erlang BEAM是Erlang的一個獨特特性。BEAM的構建方式是可擴充性、容錯性、分布性、並發性等的基礎保證。

Erlang如何擴充?與作業系統中的本地線程不同,BEAM可以支援稱為綠色線程的輕量級進程,這些進程通常是使用很少的本地作業系統線程分離出來的。從字面上看,可以從任何一個本地作業系統線程中分離出一百萬或更多的Erlang進程。通過將大堆塊分配給本地線程並在多個Erlang進程間共用,使這一點成為了可能。每個Erlang進程都會獲得一塊來儲存它的所有變數。由於它的大小可能只有233個字,本地作業系統線程的堆完全可以應對一百萬個進程。此外,由於Erlang內建的非同步訊息傳遞,進程之間的通訊幾乎不是瓶頸。一個進程永遠不會被阻塞,以便向其他進程發送訊息:它或者試圖擷取對另一個進程信箱的鎖定,直接將訊息放入其中,或者將訊息放入單獨的堆片段中,並將該堆片段附加到其他進程堆。Erlang虛擬機器還具有內建的分布功能,可以運行進程並以透明的方式跨機器與它們進行互動。 

並發在Rust中如何工作?當您使用本機作業系統線程時,它們是由作業系統發送器調度的。當您使用本機作業系統線程時,它們將由作業系統發送器調度。例如,如果在Linux下,調度效率隨著線程數量而下降。但是,Erlang的BEAM從一個本地作業系統線程中分離出並管理多個綠色線程。在預設情況下,每個進程被指定2000衰減(erlang中的每個操作都有一個衰減預算,其中1衰減大致相當於一個最小函數調用),直到分配的衰減額耗盡前都允許運行,隨後搶佔為止。搶佔時,運行隊列中的下一個Erlang進程將被安排運行。這就是每個Erlang進程的調度方式。

BEAM層是如何進行記憶體管理的?正如我們所提到的,每個本地作業系統線程的堆在多個Erlang進程之間共用。無論何時Erlang進程需要更多記憶體,它都會在本地作業系統線程堆中尋找可用記憶體並拿到它(如果可用)。否則,根據請求的資料類型,特定的記憶體 Clerk服務會嘗試使用malloc或mmap從OS擷取一塊記憶體。BEAM通過將記憶體塊劃分為多個載體塊(由分配器管理的記憶體塊的容器)和每個Erlang進程與正確的載體一起提供,從而在多個進程中有效利用了這塊記憶體。根據當前的需要,如從網路通訊端中讀取大量XML節,BEAM會動態地計算出應該分配多少記憶體,分配記憶體的載體數量,GC周期釋放之後保持多少載體等等。釋放的記憶體塊幾乎在重新分配後就會立即合并,這樣下一次分配就會更快了。

Erlang垃圾收集如何工作?Erlang提供了一個每進程記憶體回收行程,它使用分代標記清除記憶體回收演算法。與Erlang內建的不分享方式想配合,收集一個進程的垃圾不會以任何方式幹擾其他進程。每個進程都有一個年輕的堆和一箇舊堆。年輕堆的垃圾收集更頻繁。如果有些資料在兩個連續的年輕記憶體回收周期中存活,它將被移至舊堆。只有在達到指定大小後,舊堆才會被記憶體回收處理。 

Erlang的容錯是如何工作的?Erlang認為失敗是不可避免的,它試圖做好處理準備。任何普通的Erlang應用程式都需要遵循一個監督層級,在這個層級中,每個Erlang進程都需要一位監督者予以監督。監督者負責根據故障類型重新啟動其控制下的背景工作處理序。監督者還可以根據工作人員監控的類型對工作人員配置重啟策略,例如一對一(每個背景工作處理序退出僅關係到一個背景工作處理序),一對多(如果一個背景工作處理序退出,則重新啟動所有背景工作處理序)等。BEAM提供連結以在進程之間傳播退出訊號,以及監視器以監視在相同BEAM VM內的進程之間傳播的退出訊號,並且還可以跨越分布式的BEAM Vm透明地傳遞位置。Erlang的BEAM還可以一次在一個虛擬機器或所有虛擬機器上動態載入代碼。BEAM負責載入記憶體中的代碼變更並應用它們。告訴BEAM有關載入模組的順序、狀態管理等所需的額外努力,以防止任何未確定的進程狀態。

與Erlang相反,Rust在編譯器時完成了大部分工作,而在運行時只做了很少的工作。由於大多數系統程式設計語言在運行時缺乏記憶體安全性,因此Rust會儘力確保代碼編譯完成後在運行時沒有問題。雖然BEAM以運行時確保記憶體安全,但有時開銷會變得異常複雜,所以Rust選擇在編譯時間。

Rust的核心語言特性就是旨在儘可能簡潔。舉個例子:Rust常常在晚上構建具有輕量級的綠色線程(類似於Erlang進程)。在某一時刻,該特性被有意識地刪除了,因為它不被視為每個應用程式的通用需求,並且它伴隨著一定的運行時成本。相反,該特性可以在需要時通過crate提供。雖然Erlang也可以匯入外部庫,但其核心功能(如綠色線程)嵌入到VM中了,不能關閉或使用本地線程進行交換。儘管如此,Erlang Vm的綠色線程效率非常高,近幾十年早已證明了這一點,關閉它對於選擇使用Erlang的人來說不是一個常見的要求。

Rust如何擴充?擴充限制通常取決於通訊和分發機制的可用性。至於通訊機制,基於訊息傳遞和每個進程垃圾收集和ETS的Erlang模型是否比Rust擁有單一所有權和共用變異的渠道更有效率是值得商榷的。 

在Erlang中,任何訊息都可以通過複製發送到所有其他進程。垃圾收集器在發送和接收過程中都進行了大量清理工作。而另一邊,Rust的渠道是多個生產者和單一消費者。這意味著如果訊息發送給消費者,則不會將其複製並將其所有權轉移給消費者。然後,消費者在其範圍的末章節附註入清除代碼以回收這個值。通過為所有通道複製這個值,可以向多個消費者發送相同的訊息。在某些情況下,Rust的所有權模型與可預測的記憶體清理相結合可能會比Erlang的垃圾收集更好。 

通訊的另一個重要方面是共用突變。從理論上講,Erlang:的ETS與聯合使用Rust共用突變與互斥體和引用計數類似。但是,儘管Rust具有非常細粒度的突變單位,它就像Rust變數一樣小,但Erlang的ETS中的突變單位處於ETS表層級。另一個重大差異是Rust缺乏內建的分配機制。

在Rust中是如何並發的?Rust線程預設為本地線程。作業系統使用自己的調度機制來管理它們,因此它是作業系統的屬性,而不是語言的屬性。擁有本機作業系統線程可以顯著提升網路,檔案IO,加密等作業系統庫的效能。或者,您可以使用一些綠色線程或內建發送器的協同庫,你可以有足夠的選擇。不幸的是,目前還沒有穩定的crate。Rayon是一個資料並行庫,它實現了一個工作竊取(work-stealing )演算法來平衡本地線程間的負載。 

Rust是如何做記憶體管理的?正如所討論的,它使用所有權和生命週期的概念進行了大量靜態分析,以確定哪些變數可以分配到堆棧以及哪些分配到堆。Rust在這裡有一件事做得很好,它嘗試在棧上分配儘可能多的資料,而不是在堆上。這在很大程度上提高了記憶體讀取/寫入速度。

垃圾收集是怎麼做的?如上所述,Rust在編譯時間標記並確定變數的生命週期。此外,Rust使用的大多數變數都傾向於存在於堆棧中,這更易於管理。在Erlang中,垃圾收集器必須在給定的時間間隔內觸發,以便在整個堆中尋找未使用的資料,然後釋放它。在允許共用引用的語言中,如果沒有任何警告,這會變得更加困難,例如Java。垃圾收集期間的可預測性很難在這些語言中實現,Java的可預測性比Erlang低,而Rust的可預測性比Erlang更高。

容錯是如何工作的?Rust本身沒有內建的機制來識別運行時失敗並從中恢複。Rust通過Result和Option類型提供了基本的錯誤處理,但這不能保證永遠都能處理每個意外情況,除非您的語言中嵌入了執行階段錯誤管理架構。Erlang在這一點佔了上風,通過貫徹使用其監督架構和熱代碼載入它可以提供至少五個九的正常已耗用時間。Rust要做到這一點還得再加把勁兒才行。

結論

Erlang和Rust在各自的領域都很強大。Erlang已經存在有很長一段時間了,並且在可擴充性、並發性、分布和容錯方面已經證明是一個強大且行業就緒的生態系統。Rust具有自己定義的特性,如能在低層次運行且具有可利用本地效能的進階語言特性,安全編程以及常見特性(如並發支援和針對錯誤處理的規定)。

在我看來,如果一些非常複雜的用例需要上述所有特性,一個有趣的選擇是將Rust與Erlang一起結合起來作為共用庫或本機實現的函數(NIF)。所有的資料處理、IO操作、作業系統調用都可以甩給Rust,然後將結果同步回Erlang虛擬機器。這樣做的目標是使事情更容易。

Rust是Erlang的替代品嗎?我的答案是,不是。幾十年來,Erlang BEAM已被證明具有出色的可擴充性、並發性、分布性和容錯性。Erlang一直都在嘗試通過BEAM處理它們,把這許多共性問題提取出來,好讓程式員不需要分心去考慮它們,從而可以專註於手頭的問題。相反,對於Rust來說,我們可以通過社區建立的crate獲得很多選擇,但作為程式員,我需要以正確的方式將它們混合使用。Rust的另一大挑戰是其陡峭的學習曲線。對於剛剛開始或來自動態程式設計語言的人來說,這絕對是一個更大的飛躍。簡而言之,這兩種語言針對不同的受眾並解決不同的問題,而將它們擅長的部分捏合起來可能是最好的做法。

關於作者

Krishna Kumar Thokala目前在Thoughttworks擔任應用程式開發人員。此前,他作為開發人員曾在Erlang的電信網路模擬器上工作過一段時間,作為架構師,他使用NetConf上的 yang modeling 構建了一個組態管理系統。除了構建軟體系統外,機器人技術/電子技術和工業自動化也是他感興趣的領域。你可以通過這幾個社交平台關注他:Medium、LinkedIn、Twitter

查看英文原文:A Comparison Between Rust and Erlang

本文永久更新連結地址:https://www.bkjia.com/Linux/2018-03/151574.htm

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.