PyPy JIT 的改善

PyPy 這邊看到 JIT 的重大進展:「Better JIT Support for Auto-Generated Python Code」。

他們在 Tornado 上重製出來效能問題,後面也都是用這個例子在測試:

If you render a big HTML template (example) using the Tornado templating engine, the template rendering is really not any faster than CPython.

看起來上的 workaround 是在撞到 trace limit 時標記起來,之後再遇到時就可以跳進 special mode,接著處理下去避免浪費掉之前處理過的 trace:

After we have hit the trace limit and no inlining has happened so far, we mark the outermost function as a source of huge traces. The next time we trace such a function, we do so in a special mode. In that mode, hitting the trace limit behaves differently: Instead of stopping the tracer and throwing away the trace produced so far, we will use the unfinished trace to produce machine code.


看起來這個概念有打算在 3.8 的時候放進去:

The work described in this post tiny bit experimental still, but we will release it as part of the upcoming 3.8 beta release, to get some more experience with it. Please grab a 3.8 release candidate, try it out and let us know your observations, good and bad!

Django 的 template engine 不怎麼快,用 Jinja2 可能是一個方法,但既有的 project 如果有遇到 template engine 的效能問題,也許也可以翻看看 PyPy 解得如何...

在本機用 pip 直接安裝 PostgreSQL server

看到 PostgreSQL 官方站台上的介紹,可以直接用 Pythonpip 指令安裝 PostgreSQL server:「Install a local, non-root PostgreSQL Server with Python "pip"」,專案在「postgresql-wheel」這邊。

GitHub 上面的說明跑了一下,還真的可以惡搞... 這樣如果真的要在 CI 裡面跑的話也簡單很多了?只要能 pip 裝軟體就能跟你拼 XDDD

也省掉需要設定一些權限跑 Docker-in-Docker...

自架的 Google Search Proxy 伺服器專案:Whoogle Search

忘記在哪邊看到的連結,自架的 Google Search Proxy 伺服器專案:「Whoogle Search」,對應的 Hacker News 討論串也可以參考:「Whoogle Search: A self-hosted, ad-free, privacy-respecting metasearch engine (」。

GitHub 上的分析可以看出來主要是 PythonFlask 寫的,然後說明就有提到是從 Google Search 撈資料,去掉所有可能可以被追蹤的項目:

Get Google search results, but without any ads, javascript, AMP links, cookies, or IP address tracking. Easily deployable in one click as a Docker app, and customizable with a single config file. Quick and simple to implement as a primary search engine replacement on both desktop and mobile.

目前最新版是 0.5.4,從他列出來的 Public Instances 找了一個是最新版的測試,看起來沒什麼大問題:「gslin - Whoogle Search」。

應該可以自己在台灣架一個起來玩看看?安裝方式看起來很多,因為是 Python-based 的套件,可以用 pipx 或是 Docker 裝起來跑,然後可以改寫「Press "g" to Google (DuckDuckGo)」(press-g-to-google-duckduckgo) 讓他可以設定要轉到哪個 Google Search Proxy...

Elasticsearch 的 Python 套件開始阻擋 OpenSearch 的伺服器了

Hacker News Daily 上看到的:「Official Elasticsearch Python library no longer works with open-source forks (」,連結所指向的是 GitHub 上的 pull request,在「Verify connection to Elasticsearch #1623」這邊。

講白了也就是 Elasticsearch 官方的 Python client 開始阻擋 AWS 主推的 OpenSearch

另外 AWS 這邊也出手,把本來的 client 都 fork 出來:「Keeping clients of OpenSearch and Elasticsearch compatible with open source」,這場戰爭還有得打...

快速產生 SQLite 資料的方式:一分鐘內產生十億筆資料

在「Towards Inserting One Billion Rows in SQLite Under A Minute」這邊看到作者想要在一分鐘內在 MBP 2019 上面寫 1B 筆資料進 SQLite,裡面有些方法還蠻值得玩一下的,這台 MBP 2019 機器的規格是:

The machine I am using is MacBook Pro, 2019 (2.4 GHz Quad Core i5, 8GB, 256GB SSD, Big Sur 11.1)

第一版是 Python 寫的,塞 10M 筆花了 15 分鐘:

In this script, I tried to insert 10M rows, one by one, in a for loop. This version took close to 15 minutes, sparked my curiosity and made me explore further to reduce the time.

加了五個 PRAGMA 的版本變成 100M 筆十分鐘:

The naive for loop version took about 10 minutes to insert 100M rows.


The batched version took about 8.5 minutes to insert 100M rows.

再來是拿經典神器 PyPy 出來用,降到兩分半:

All I had to do was run my existing code, without any change, using PyPy. It worked and the speed bump was phenomenal. The batched version took only 2.5 minutes to insert 100M rows. I got close to 3.5x speed :)

接下來就是跳槽到 Rust 了,中間也有不少 tuning 相關的討論,但直接先跳到最後面好了... 最後 100M 只用了 33 秒:

I created a threaded version, where I had one writer thread that received data from a channel and four other threads which pushed data to the channel. This is the current best version which took about 32.37 seconds.

能用 PyPy 的地方還是可以考慮一下的...

用 Python 的 DuckDB 下 SQL 指令翻 Parquet 的資料

在「Querying Parquet using DuckDB」這邊看到 DuckDB 這個東西,裡面引用的文章是「Querying Parquet with Precision using DuckDB」,可以直接對 Parquet 格式的資料下 SQL 找資料。

先前好像有看到 DuckDB 但沒有太注意,剛剛再次看到,然後玩了一下還蠻有趣的。DuckDB 支援蠻多程式語言與資料格式,不過這邊文章拿 Python 與 Parquet 玩還蠻有趣的...

先把 Parquet 的範例資料抓下來,然後透過 pip 裝 duckdb:

cd /tmp; wget; pip install -U duckdb

然後進到 Python 3 的互動界面:

>>> import duckdb
>>> print(duckdb.query("SELECT COUNT(*) FROM 'taxi_2019_04.parquet' WHERE pickup_at BETWEEN '2019-04-15' AND '2019-04-20'").fetchall())

然後在範例裡面,檔名的部份還可以用 *,看了一下說明,底層是 glob 類的用法:

DuckDB supports the globbing syntax, which allows it to query all three files simultaneously.

文章裡有提到速度比 Pandas 快很多,不過我覺得這好像不太能這樣比,會拿 Pandas 出來的時候常常是其他用法,但至少看起來速度是個 DuckDB 在意的點。

不過反而馬上想到的是,之後處理 CSV 之類的檔案應該也會試看看 DuckDB...

Django 3.2 LTS

Django 3.2 LTS 出了:「Django 3.2 released」,對應的 release note 可以在「Django 3.2 release notes」這邊看到。

這個版本比較特別,一般版本提供大約 15 個月的支援,LTS 版本則提供 36 個月的支援,不過目前用起來的感覺還是鼓勵大家平常就要安排升級計畫,不然 3.2 升級到 4.2 鐵定是個超痛苦的過程。

昨天把 Django 3.1 的專案升級上 3.2 後,跑 test case 就遇到「Customizing type of auto-created primary keys」這邊描述的問題,目前先用 DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' 解,其他的倒是沒什麼問題...

幾個我覺得有趣的,像是 JSONL 格式:

The new JSONL serializer allows using the JSON Lines format with dumpdata and loaddata. This can be useful for populating large databases because data is loaded line by line into memory, rather than being loaded all at once.

然後不支援 PostgreSQL 9.5 與 MySQL 5.6 了:

Upstream support for PostgreSQL 9.5 ends in February 2021. Django 3.2 supports PostgreSQL 9.6 and higher.

The end of upstream support for MySQL 5.6 is April 2021. Django 3.2 supports MySQL 5.7 and higher.

很久前寫 Django 1.x,然後就荒廢很久,最近是從 3.0 開始寫,有些東西熟一點以後覺得怪怪的,之後要找時間測一些東西,修正對 Django 的用法。


Hacker News Daily 上看到「Why are tar.xz files 15x smaller when using Python's tar library compared to macOS tar?」這篇,作者問了為什麼他用 Pythontarfile 壓出來比起用 tar 壓出來小了 15 倍,檔案都是 JSON 檔壓成 XZ 格式:

I'm compressing ~1.3 GB folders each filled with 1440 JSON files and find that there's a 15-fold difference between using the tar command on macOS or Raspbian 10 (Buster) and using Python's built-in tarfile library.

看到 1440 個檔案應該會有直覺是一分鐘一個檔案,跑一天的量...

隔天他把原因找出來了,在裝了 GNU Tar 並且加上 --sort='name' 參數後,壓出來的大小就跟 Python 的 tarfile 差不多了:

Ok, I think I found the issue: BSD tar and GNU tar without any sort options put the files in the archive in an undefined order.

After installing GNU tar on my Mac with:

brew install gnu-tar

And then tarring the same folder, but with the --sort option:

gtar --sort='name' -cJf zsh-archive-sorted.tar.xz /Users/user/Desktop/temp/tar/2021-03-11

I get a .tar.xz archive of 1.5 MB, equal to the archive created by the Python library.

底層的原因是檔名與檔案內容有正相關的相似度 (因為裡面都是 sensor 資料),依照檔名排序壓縮就等於把類似的 JSON 檔案放在一起壓,使得 xz 可以利用這點急遽拉高壓縮率:

My JSON files contain measurements from hundreds of sensors. Every minute I read out all sensors, but only a few of these sensors have a different value from minute to minute.

By sorting the files by name (which has the creation unixtime at the beginning of it), two subsequent files have very little different characters between them. Apparently this is very favourable for the compression efficiency.

遇到類似的情境可以當作 tuning 的一種,測試看看會不會變小很多...

Raspberry Pi 推出 MCU 產品 Pico

Raspberry Pi 推出了新的產品線 Raspberry Pi Pico,基於 ARM 架構的 MCU (microcontroller unit),Hacker News 上也有不少討論:「Raspberry Pi Pico and RP2040 Microcontroller (」。

與 Raspberry Pi 的 Zero 系列比起來,Zero 上面有 512MB RAM,不算大但還是可以跑一個完整的 OS。而 Pico 的定位就直接是 MCU 了,基本上就是特製的系統。

再來是看 Pico 的規格,比隔壁棚的 ESP32 低一些,但可以看出來 Pico 主要的定位還是教學:高速雙核心 CPU、多腳位、大的記憶體以及 flash (對於一般量產的 MCU 來說),支援透過 Micro-USB 的 5V 供電界面方便開發與使用。

官方支援 CMicroPython 兩種開發使用的模式,其中在 Hacker News 上有人抱怨 MicroPython 哭爸慢,不過這點應該還好,要在上面跑比較複雜的人會自己跳到 C 上面開發。

最後來講價位,目前定價是每顆 USD$4,當然跟一般商用量產的 MCU 差不少 (會盡可能壓低到「剛好夠用」的等級,價錢就有可能低到 USD$0.x),但相比於現在在教學上很紅的 ESP32 (大約在 USD$10 附近) 來說,等於是殺出另外一條產品線,加上挾帶著 Raspberry Pi 的知名度來說,等於是讓更多人熟悉 MCU...


Hacker News Daily 上看到的文章,在講一人團隊時所設計的技術架構:「The Tech Stack of a One-Man SaaS」。這種資訊通常帶有個人偏好,維護成本算是蠻重要的重點,在多人團隊就未必會這樣選,但就拿著爆米花看戲的心態來說應該還 OK。

像是作者很明顯熟悉 Python,就可以看到他裡面會列出許多 Python 相關的 toolchain 與維護工具。

裡面比較有趣的是他對 DigitalOcean 的 K8S 問題很多抱怨了一番,然後換去 Linode 後又因為不想要自己管 PostgreSQL 而決定搬到 AWS 上面,可以用 RDS 省事... 花錢解決 XD