Asus Zenbook Ux510ux 與 Ubuntu 無線網路

最近處理一台筆記型電腦, Asus Zenbook Ux510ux 。在上頭用 WUBI 安裝 Ubuntu 16.04 ,最後遇到無線網路的毛病。

本來在 Asus 筆電 Windows 10 環境之下,打算開始安裝 Ubuntu 的時候,必須先調整 BIOS 把安全開機功能關閉:作法如下,

  1. 開機進入 Windows ,然後打開功能表,滑鼠移到「重新啟動」按鈕上。
  2. 手指按住鍵盤 Shift 鍵,然後按下「重新啟動」,等著關機過程之後會進入特殊的藍色選單畫面。
  3. 點選「疑難排解 > 進階選項 > UEFI 韌體設定」,等著電腦重新開機之後,會進入 BIOS 設定畫面。
  4. 在 BIOS 選單裡找「 Security Boot 」設定項目,修改設定值為 Disable 。

而我在做這些設定時,順勢將許多功能檢查過一次,並且調整為 Enable 。以「 Network Stack 」子選單來說,我把「 IPv4 PXE Extension 」與「 IPv6 PXE Extension 」都 Enable 了。

然後, Ubuntu 安裝好並且啟動之後,用 $ rfkill list 看無線設備的狀況,老是看到 phy0 代號的設備為 Hard blocked: yes 。於是就去研究了一陣子,包括網卡型號 Intel Dual Band Wireless-AC 7265 、驅動程式 iwlwifi 及 iwlmvm 、無線網路功能按鍵 Ctrl-F2 、網路功能指令 $ rfkill unblock all 等等各種零碎知識,但找不出總和的解決辦法,來讓 Ubuntu 能連上網路。

後來,發現我只要回去 BIOS 設定程式裡,在「 Network Stack > IPv6 PXE Extension 」設定為 Disable , phy0 就變成 Hard blocked: no , Ubuntu 就可以連上網路了。

 

廣告
張貼在 Uncategorized

程式模式的比喻

最近做一點分散、平行處理的程式工作,有一點感覺:

如果循序處理像是幾個人負責跑一段接力賽跑,總共跑多久,是所有每個人各自跑多久的總和,

那麼,

平行處理,是幾個人都一起從起跑點開始賽跑,大家總共跑多久,要看跑最慢的那個人跑多久。

分散處理,則是幾個人先玩搶椅子遊戲,然後,搶到椅子的人都已起從起跑點開始賽跑。

張貼在 Uncategorized

Python 資源描述

Python 資源描述,我指的是像 import a.b.c 的 a.b.c 表達法。

就 a.b.c 的表達格式, c 所指的可能是資料夾( a/b/c/__init__.py ),可能是檔案( a/b/c.py ),可能是物件或屬性、物件方法等等。

就以上表達格式的應用場合, import a.b.c 指 c 可能是資料夾或模組檔案(模組就是檔案,檔案就是模組),而在程式行裡看到 a.b.c 則是指其他東西。

以上好比 pathlib.Path(…) 將資料夾路徑與檔案路徑整合為一個純粹稱為路徑的東西,作為思考介面,能幫助我們理解程式內容。

至於 pathlib.Path(…) ,如果表達得再深入一點,可以說,例如 pathlib.Path(‘a/b/c.zip/d.csv’) 能整合 zip 的資訊,或者用 pathlib.Path(‘a/b/c.xml/d/e/f’) 能整合 XML 的資訊,那麼,就更簡便了。

張貼在 Uncategorized

Python 整批資料填入 MySQL

百萬到千萬行資料要填入資料庫,想起來感覺很難。

MySQL 的大量資料輸入,說明書的討論大概提出二個路線:

  1. Load data infile 命令
  2. Insert [delayed] into Table Columns values Values, Values, …, Values;

我選擇第二個方法,但不使用非同步處理。

我試著以 MySQL 環境參數 bulk_insert_buffer_size 數目為基礎,以預設值 8 MB ,將資料拼湊為每 8 MB 為一段,填入資料庫,接著發現:有些資料庫可以,但有些資料庫不行。

Python 程式遇到執行失敗的 SQL ,還是老樣子:卡著讓你看。這也是使我覺得最絕的部分, Python 做為一份程式語言,所寫出來的程式可以執行在一半的時候停著不動。我猜都是因為它在 client-server 情境中,身為代理人,在提出請求之後除了進入等待的狀態以外,也不能想任何辦法給自己解除狀況。

那麼,使用了 pymysql 執行 SQL ,卻卡住了,怎麼辦呢?

真相是,要按照另一個環境參數,叫 max_allowed_packet ,來衡量一次送出多少長度的 SQL 。

MySQL 有三個參數,對於系統的容受能力,為不同的控制因素:

  1. max_allowed_packet :一次能處理的 SQL 文字長度,這是介面的控因。
  2. bulk_insert_buffer_size :屬於大量資料填入的演算法的控因。
  3. key_buffer_size :是處理表格欄位索引的演算法的控因。
張貼在 Uncategorized

Python 速度要項

目前在寫資料 ETL 的系統程式,做了一個月,差不多能掌握的都夠了。

處理大量資料,最容易被要求、挑戰的就是執行速度。在 Python 來說,我感覺,速度不只端看程式的速度,而是搭配著看執行環境與系統。

在追求速度方面,寫程式的生存、自救要點,我覺得有以下幾項:

  1. 寫程式同時順便要做好速度量測的基礎,也就是資料率:速度是相對的,不同的電腦之間,同一份程式,慢的電腦跑得久,快的電腦跑得時間短。小時候學物理學,第一課就是在教我們識別各種單位表示與意義。同理,做大量資料處理,資料率是個很重要的東西。至少,我們要知道全部的資料有多少行,以及每一單位時間可以處理掉多少行。而所謂「需要多久可以跑完」這種模糊的標準,則是流水浮雲,請記得:時間是相對的。
  2. 不要把每一行都印出來:每一行電腦程式,依運作的特性,可以區別為 CPU-bound 與 IO-bound 等類型(我看可能這年頭,可以說有 NIO-bound 、 Cloud-bound 之類的,至少我看 ETL 的 Load 動作,要面對 MySQL-bound 的程式),好比 SATA 硬碟不會跟 IDE 硬碟接在同一條排線的概念,當你的一段程式夾雜了很多 IO 的程式行數,那一段程式就是 IO-bound ,速度會讓 IO 拖慢。而另一個不要每一行都印出來看的理由,是因為大量的資訊印出,我們的動態視力與注意力都跟不上,所以別白費工夫。
  3. 不同的 class 是不同的演算法:學習 Python 要多多運用 type(…) 或 module inspect ,來認識我們所能寫下的各種資料的本質。好好練過幾次,我們可以得到印象: str, list, dict, set 等等,各自包含了各種操作方法,代表了不同的演算法、有不同的速度。 str.find(…) 及 str.rfind(…) 分別用來搜尋二端的子字串,比 re.match(…) 快, list 方便連續串聯資料, dict 方便快速從中間添加或刪除資料,還有, dict 和 set 的查詢都比較快。迴圈方面, enumerate(…) 做資料列舉比 dict 快、 dict 做資料列舉比 list 快。
  4. 跟著資料的特性做資料處理:如果有一批資料的變動量極少,那麼,我們應該給這批資料用 set 或 dict 做個查詢表,給新來的一批資料找出差集合,那麼,所找出的差集合的資料量相當少,而且是所需處理的資料量。
  5. 跟著所要的流程裁切掉不必要的動作:通常寫程式的人都愛用模組化,或將同一程式格式 copy-paste 而產生另一份程式。組裝式、軟體工程式的程式,會帶來一些比較僵化的結構,也許就在結構中存有依些浪費時間的流程死角。程式寫得差不多要完成了,輪到了檢查程式執行速度的階段時,我們可以藉由反省口說的流程(不是程式的流程)、適當地打破格局,來重寫出比較快速的程式。在那之前,可以將程式拆解,借註解符號停用一些動作,來分析幾個零星段落的具體速度,最好能細緻發現到平均每一行消耗多少微秒。將每個動作單元每一行所消耗微秒數列出為列表,能幫助我們好好構想,並且可能從正規的軟體開發階段,跳躍到奇技淫巧的設計階段。或許你會發現,每一行都用好幾個 function application 做 extract ,會多消耗 20 ms ,那麼,那些漂亮的 lambda expression 就是需要清掉的東西。
  6. 別忘了傳統的節能、加速辦法:例如不要在迴圈的每一行都 try-except 一次,要在迴圈之外一次包覆 try-except 格式,會跑得比較快。
  7. 對於習慣不經意看待的東西,留一點時間多想好幾次:例如我有個程式段落寫成 dict([ x for x in dict(d) if x not in set(s) ] + [ (‘a’, ‘, ‘.join(‘hello’, ‘world’)) ]) ,這種寫法是一般 Prolog 或 Erlang 程式寫手所習慣的 generation way :我們手上已經有一個 dict d ,卻將它拆開然後重做成一個新的 dict d’ ,這是個很消耗時間的方法。若我們切換為減法思維,則是以從 dict d 裏頭刪除不需要的 key-value 著手, d.pop(k) 的速度相當快,用不同的方式達成相同的目標,而且獲得速度。

如以上,連番努力過好幾輪,相信我們的白髮都發得比較多。我認為白髮是一種榮譽。

張貼在 Uncategorized

Python dbConnect V.S. pymysql

今天發現,在用 Python dbConnect 的時候,裡頭一路用到 mysql-connector 甚至 socket 的 sock.recv 會有卡住的情況。我感覺,似乎是跟著連線的可容狀態 (capacity) 有關。

後來,改看一下 pymysql ,沒有類似的問題,也不需要依賴 mysql-connector 。

張貼在 Uncategorized

Python ftplib 下載大檔案會卡住

我工作時,遭遇了用 Python 程式下載 500 MBs 的檔案之後會卡住。後來找到解決辦法。討論如下。

程式環境是 Windows 10 及 Python 3.5.1 。

以下程式,出現下載之後卡住。

def _show_progress(data, fo, fsize, mod_name):
    fo.write(data)
    print_progress(fo, fize)

def _retr_callback(fo, fize, mod_name):
    return lambda data: _show_progress(data, fo, fsize, mod_name)

ftp = ftplib.FTP()
...
fsize = ftp.size(src)
...
with open(target, 'wb') as fo:
    ftp.retrbinary('RETR ' + src, _retr_callback(fo, fsize, __name__))

研判卡住的位置是 ftp.retrbinary(…) 內。經過等待之後,進度條停在 100% ,而程式卡住不走下一步,而且,按了 Ctrl-c 也無法退出程式。

我設想,應該是 ftp 做為代理人,因為 retrbinary(…) 時不與 FTP server 溝通的時間太久,後來 ftp 代理人突然要講話的時候,叫了 FTP server 但是對方不回應,於是 ftp 代理人一直在等待對方回應。

解決辦法是在 retrbinary(…) 的 callback 裡頭,加上 ftp.voidcmd(‘NOOP’) ,讓它經常去給 FTP server 點一下、點一下。

所修改的程式如下:

def _show_progress(data, ftp, fo, fsize, mod_name):
    fo.write(data)

    ftp.voidcmd('NOOP')
    print_progress(fo, fize)

def _retr_callback(ftp, fo, fize, mod_name):
    return lambda data: _show_progress(data, ftp, fo, fsize, mod_name)

...

with open(target, 'wb') as fo:
    ftp.retrbinary('RETR ' + src, _retr_callback(ftp, fo, fsize, __name__))

而在 callback 之內增加 ftp.voidcmd(‘NOOP’) 的效果,會讓進度條的更動次數變慢。 IO 拖延了,完成 FTP 下載檔案的時間也會久一點。

張貼在 Uncategorized