看過來

初來乍到者,請參閱這篇「緣起」。它是總索引!

2017年6月26日 星期一

[Rust] 單元測試與效能基準測試 (benchmark) :以某遞迴問題為例

這是在 PTT C/C++ 板上面看到的問題 (https://www.ptt.cc/bbs/C_and_CPP/M.1498011747.A.BC3.html),摘錄問題描述如下:

輸入       得到
(n) -> 1 (n-1)(n-1)

例如
(0) -> 0
(1) -> 100
(2) -> 1100100
(3) -> 111001001100100

或者把定義的部份寫成

f(0) = "0"
f(n) = "1" ++ f(n-1) ++ f(n-1)

(假設 ++ 是字串接合運算符號)

自問題描述可以看出這是遞迴定義。怎麼說?因為第 n 個結果是利用第 n - 1 個結果組合而成。

這樣的問題可以用直覺遞迴來解,也可以寫成迴圈來解,也可以用動態規劃來解。

在實作完上述的演算法後,可以利用自動測試來測試演算法的實作是否沒問題。而為了比較這些實作之間在各種場合下的優劣,可以利用效能基準測試(benchmark)來互相比較。

非常幸運的是,Rust 的基本開發工具裡面已經包含了這些工具。單元測試的部份,可以在第二版的 Rust 程式書找到:https://doc.rust-lang.org/book/second-edition/ch11-00-testing.html 。至於只在 nightly 才有的效能基準測試,則在第一版的書裡面 https://doc.rust-lang.org/1.4.0/book/benchmark-tests.html

千秋所做的程式碼在 https://gitlab.com/chiakikame/rust-recurse-algorithm-fun 可以找到。因為千秋也在學習中,歡迎諸位大德不吝指教以及討論。


2017年5月21日 星期日

Java

超簡單介紹

Java 是一個以安定嚴謹為目標的的物件導向靜態型別程式語言。因為語法的相似度,所以常常被拿來與 C++ 做比較。在初期,常常被詬病的是它的效能:由於 Java 寫成的程式成品必須在 Java 虛擬機器(JVM, Java Virtual Machine)上面執行,而初期的 JVM 設計並不如現在的好。所幸此問題現在已經獲得了不小的改善。現在,比較新的 JVM 裡面會包含 JIT 編譯功能(即時編譯, just-in-time compilation),以及非常強大的垃圾回收模組 (garbage collector, GC)

開發工具

開發 Java 軟體的人,絕大多數都會使用整合開發環境。目前比較知名的整合開發環境有:
  1. NetBeans IDE
  2. Ellicpse
  3. IntelliJ IDEA
所有最基本的功能(例如程式碼自動完成)三者均具備。可以依照個人口味來挑選。

若講到建置 Java 程式的工具,除了整合開發環境可能內建的以外,還有如下三者:
  1. Ant
  2. Maven
  3. Gradle
現在已經比較少人使用 Ant 了。大多數人都使用 Maven 以及 Gradle。Maven 以及 Gradle 優秀的地方在於他們有一套程式相依管理規則,附帶可以自動於建置時去網路上的套件庫下載相依套件的功能。

學習資源

Java 因其歷史悠久,學習資源不勝枚舉
在學習 Java 時,要注意 Java 6 ~ 8 之間的語法以及標準程式庫之間有些的差異。

相關程式庫

不要忘了也去 https://github.com/akullpp/awesome-java 找找看!
  • 基礎
    • Vavr
      Functional programming library for Java8+
  • 框架
    • Vert.x
      提供事件驅動,non-blocking 程式設計模型的框架。附帶可以用來設計網路程式的客戶端以及伺服器端。

  • 網路程式設計
  • 檔案格式
  • 單元測試
    • JUnit
      自成標準的單元測試程式庫
    • AssertJ
      Fluent assertion library
  • 紀錄 (Logging)
    • slf4j
      整合並抽象化了多種 logging 方式的程式庫

2017年5月6日 星期六

[CentOS] CentOS 7 最小安裝 (minimal install) 於虛擬機上的設定

要進行網路程式開發,弄個虛擬機是一個很好的手段。然而要是安裝整個桌面系統則相當笨重,所以帶有最小安裝設定的發行板是最好的。

網路設定


取得 CentOS 7 的最小安裝光碟映像檔後,在虛擬機器上面安裝了 CentOS,結果發現沒有網路連線。想查狀況卻發現沒有 ifconfig。好吧,該怎麼辦呢?

還好是虛擬機器,主作業系統當然還可以使用。查詢之下發現最小安裝的時候沒安裝 ifconfig,因為可以用 ip a 來查詢連線以及網路卡狀況。

用 ip a 查詢後發現虛擬機器沒有被分配到 ip 位址。更進一步使用 nmcli d 查詢後發現 eth0 的網路連線沒有被啟動。利用 nmtui ,跟著畫面來操作之後,執行 service network restart,用 nmcli d 確認發現現在有網路可以使用了。

Keymap 設定


安裝時誤選了 uk 鍵盤,沒辦法打篩管記號,所以利用 loadkeys us 更正這項設定。

LAMP 設定


接著設定 LAMP (中的 AMP) LAMP = Linux + Apache + MySql (MariaDB) + Php

利用 sudo yum install php httpd mariadb-server 來安裝上述材料。

完成後,使用下面的指令來啟動服務

sudo systemctl start httpd
sudo systemctl start mariadb

接著設定成開機時也啟動

sudo systemctl enable httpd
sudo systemctl enable mariadb

(附帶一提,使用 systemctl list-unit-files 可以查到當前在系統上所有的服務)

設定完後,使用 curl localhost:80 可以看到 httpd 的預設網頁,說明 httpd 已經成功安裝,然而從主作業系統中使用 curl (ip):80 取得一樣的結果,所以需要修改防火牆。

(附記,ssh (ip) 可以連到客作業系統)

先確認當前所在的 zone:

firewall-cmd --get-active-zones

CentOS 預設的 zone 似乎是 public,所以

sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --reload

然後就可以在主作業系統用 curl (ip) 取得網頁了!

2017年3月30日 星期四

[Rust] Rust 預設堆疊大小

本文討論到 Rust 程式的預設堆疊大小,那這裡的堆疊是指什麼?

Rust 和 C 語言一樣,若是宣告了自動變數(區域變數),那麼區域變數本身的空間必須由堆疊來供應。此外,進行函數呼叫的時候,為了保存返回位置,也需要使用堆疊。

(附帶一提,在 Rust 中,若想要進行動態分配,則必須使用 Box<T>; C 裡面則要使用 malloc。Rust 的 Vec<T> 內部使用了 Box<T>,所以可以達成動態大小。)

所以說,若您的程式需要很大的陣列空間,或者是會進行遞迴呼叫,那您可能會遇到堆疊空間不足的問題。所以了解堆疊空間限制,以及調整的方法就變成了重要的課題。

實務上來說,若能夠在編譯時調整堆疊空間(像是 C 語言),或者最起碼可以在啟動時調整(像是 JVM),則可以不用了解堆疊空間限制在哪裡,不夠的時候直接調整便可。然而,對 Rust 來說,目前似乎仍然沒有可以調整主執行緒(main thread)堆疊大小的方法:
雖然沒辦法調整主執行緒的堆疊大小,但是在 Rust 裡面,我們可以調整新生成執行緒的大小。利用這樣的原則,我們不只可以在發覺主執行緒堆疊不足時迴避此問題,還可以藉著比較已知堆疊大小的新執行緒以及主執行緒會發生堆疊溢滿(Stack overflow)的函數呼叫次數來推得一個系統的預設堆疊大小。

利用上面的概念,千秋設計了一支程式,它可以:
  • 示範如何調整新執行緒的堆疊大小
  • 利用 command-line switch ,您可以選擇測試主執行緒的堆疊大小,或是新生執行緒的堆疊大小,並且可以指定新生執行緒的堆疊大小
此程式所測試的堆疊大小,不是以具體大小來呈現,而是以「可以遞迴呼叫某函數幾次」來呈現。

此程式之程式碼倉庫位在 https://gitlab.com/chiakikame/rust_stack_size

2017年3月19日 星期日

[Rust] 在 GNU/Linux 的機器上產生 Windows 64-bit 執行檔

若是可以在 GNU/Linux 下面產生 Windows 的執行檔該有多好...

前置作業

  • 安裝 mingw64
    如果您也是 OpenSUSE 的使用者,您可以參考此文
  • rustup target add x86_64-pc-windows-gnu

設定

在 Linux 下面預設的 linker 是 gcc,但是編譯成 x86_64-pc-windows-gnu 執行檔時 linker 也是,怎麼辦呢?

請把如下的內容放到 ~/.cargo/config 中

[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32-gcc"

接著就可以開始編譯了:

cargo build --target=x86_64-pc-windows-gnu


參考資料

https://github.com/rust-lang/rust/issues/32859

[OpenSUSE] 安裝 MinGW 工具

若想要在 OpenSUSE 上安裝 cross compile 到 Windows 的必需品 mingw64,則可以照著如下設定進行
  • 前往 https://build.opensuse.org/repositories/windows:mingw:win64
  • 找到您的 OpenSUSE 版本,複製 Go to download repository 字樣上頭的連結
  • 打開 YaST2 的 Software Management 模組
  • 在目錄上找到 Configuration -> Repositories
  • 在彈出的視窗上選擇 Add
  • 在新出現的視窗上選擇 Specify URL,按下 Next,接著貼上剛才複製的 URL,選擇 Ok
  • 等 YaST 完工後便可以尋找並且安裝 mingw64 的軟體包了

[Rust] cargo.lock 究竟該不該放入 git 倉庫?

撰寫 rust 程式時,使用 cargo init 或是 cargo new 來初始化一個新的專案。新初始化的專案中已經設定好本地 git 程式倉庫,並且附帶了 .gitignore 檔案,省去了不少設定上的麻煩。

然而,執行檔專案(cargo init --bin)以及程式庫專案的 .gitignore 內容卻不一樣:程式庫專案的 .gitignore 指出,Cargo.lock 不會被放入 git 程式倉庫中;執行檔專案則相反。這是為何呢?

依據 Cargo guide 所述,cargo.lock 是描述一個專案建置時所使用的所有完整相依條件。(跟 yarn.lock 很像。)這也就是說,cargo.lock 裡面紀錄了你的相依元件的版本(cargo.toml 只有版本要求,例如某個版本以上,或是範圍內),以及你相依元件的相依元件的版本。

總之您可以利用 cargo.lock 裡面的資訊來說明您開發時所使用的所有相依元件的版本恰為多少多少。若使用和 cargo.lock 內相同版本的元件就可以成功進行編譯。

上面所描述的「版本鎖定」可以對執行檔的所有相依元件進行版本鎖定,確保在別台機器上面可以重現建置,甚至執行結果。因此我們在撰寫執行檔專案時,必須把 cargo.lock 放入 git 程式倉庫中。

但如果是程式庫呢?若是使用 cargo.lock 來限制程式庫的相依元件版本,則本身作為其他程式(下稱主專案)相依元件的程式庫本身的相依元件可能會和主專案的其他相依元件,或是其他相依元件的相依元件有版本衝突。所以在撰寫程式庫專案時,不能把 cargo.lock 放入 git 程式倉庫中。

參考資料

http://doc.crates.io/guide.html#cargo.toml-vs-cargo.lock
http://doc.crates.io/faq.html#why-do-binaries-have-cargolock-in-version-control-but-not-libraries