高速化の仕組み

FireDucksの高速化の仕組みはふたつあります.ひとつめは中間言語上でのコンパイラ最適化,ふたつめはバックエンドによるマルチスレッド高速化です.

コンパイラ最適化

FireDucksでは実行時コンパイラの仕組みを使い,Pythonプログラムを中間言語に変換してから実行します.中間言語上での最適化とは,Pythonプログラムから変換された中間言語をそのまま実行するのではなく,プログラムの意味を変えない範囲で,より効率的に実行することができる計算方法に処理を変換することです.これは熟練者がプログラムを書くときに行うようなチューニングを自動で行うことに相当します.

FireDucksの中間言語はデータフレーム専用に設計されており,中間言語上の各命令は,データフレームに対する操作を表した抽象度が高く情報量の多い命令となっています.そのためFireDucksが搭載する実行時コンパイラは,プログラムの意味を俯瞰的に把握することができ,データフレーム処理に特化した最適化を行うことが可能なのです.

最適化の例

このような最適化の例をひとつ紹介します.以下のコードでは,データフレームdfからa列の値が10より大きい行を取り出し,その後にb列を取り出しています.

selected = df[df["a"] > 10]["b"]

よく使われる処理で,特に問題のないコードのように見えます.しかし,このとき行を抽出する処理は全列を対象にしており,もしデータフレームがa, b以外にも列を持っている場合は効率が良くありません.なぜならば,一般的にデータフレームでは列指向(column major)のデータ構造が用いられており,特定の行を抽出する処理は列を抽出する処理に比べて格段に時間がかかる処理であるためです.それを全ての列に対して行うことは,無視できないオーバーヘッドになることがあります.

FireDucksの最適化は,こういったデータフレーム処理に特化した知恵を用いて,列の抽出処理を先に行うように中間言語を変換します.変換後の処理をPythonで書くなら以下のようなコードになります.

tmp = df[["a", "b"]]
selected = tmp[df["a"] > 10]["b"]

データフレームの内部構造を知る熟練者であれば,こちらのようなコードを好むでしょう.FireDucksは中間言語上での最適化としてこのような変換を自動で行います.

マルチスレッド高速化

FireDucksでは,ユーザーが利用するAPIとその実行は中間言語を境目として完全に独立しています.中間言語の命令の実行を担当する部分をバックエンドと呼び,バックエンドがデータフレームの具体的なデータ構造や演算を行う機能を持っています.

FireDucksはバックエンドを変更できるようになっており,例えばマルチコアCPU用にチューニングされたバックエンド,GPUなどのアクセラレーターを使ったバックエンドなどのように,ターゲット環境に合わせたバックエンドを利用することで高速化を行うことができます.また,バックエンドの変更は環境変数によって行うことができ,ユーザープログラムを全く変更せずにバックエンドを切り替えることができます.

FireDucksベータ版には,CPU用にマルチスレッド化されたバックエンドが含まれています.このバックエンドは,データ構造としてApache Arrowを採用し,Apache Arrowが提供するデータフレーム操作に加えて,独自の最適化を施した並列処理機能を備えています.