【Python高速化】AtCoderでCodonが使えるようになるぞー!
今回(2024-25年度)の言語アップデートで、Codonが使えるようになります!
10月下旬ごろからコンテストで利用可能になる見込みです。
それに向けて、Codonを使うメリット・注意点などをまとめました。
追加される予定のジャッジは、Language Test 202505から試すことができます。
Codonとは?
Pythonの書き心地を維持しながら、理論上はC++と同等の速度を出せます!
通常使われているPython(CPython)と比べて10~100倍の高速化が期待できるそうです。
セットアップ・使い方
1. インストール
2025年9月現在はMac・Linuxに対応しています。
Windowsをお使いの方は、WSLを使ってLinuxの環境を作っておきましょう。
このコマンドを実行して一発でインストールできます。
/bin/bash -c "$(curl -fsSL https://exaloop.io/install.sh)"
2. 環境変数を設定
CPythonのライブラリを使えるように、環境変数を設定します。
export CODON_PYTHON=/path/to/libpython.X.Y.so # 共有ライブラリのパスを指定
CPythonの共有ライブラリのパスを調べる必要があります。
詳しくは公式ドキュメントを見てください。
自分の場合(WSL)
共有ライブラリのパスはこれでした。
/usr/lib/x86_64-linux-gnu/libpython3.12.so
そのため、nano ~/.bashrc
を実行して設定ファイルを開き、
export CODON_PYTHON=/usr/lib/x86_64-linux-gnu/libpython3.12.so
を末尾に追加し、source ~/.bashrc
で読み込みます。
~/.bash_profile
に書いてもうまくいきませんでした。
(WSL自体を再起動してなかったからかな?)
3. 使い方
codon run main.py # 実行
codon build --release -o a.out main.py # 最適化をしてコンパイル
./a.out # 生成された実行ファイルを実行
CPythonとの違い
Codonでは、高速化のためにPythonの便利な書き方が一部使えません。
CやC++に近い部分が増えている、と思います。
型
Codonでは厳密に型が定められます。
- 整数はデフォルトで64ビット符号付き整数(オーバーフローがあり得る)
- 辞書の挿入順は保持されない(これはPyPyも同じ)
- タプルは固定長(例として、標準入力の値をそのままタプルに変換できない)
- リストの中身はすべて同じ型に指定
など。
ちなみに、関数の引数・戻り値の型は必須ではないようでした。
def test(a, b):
return a + b
print(test(2, 3)) # 5
print(test("a", "b")) # ab
数値計算
高速化のためにCのように計算が扱われるものがあります。
-
-10 % 3 == -1
のように、割られる数が負のとき余りが負となる
余りが負になったら、割る数を加える必要があります。 -
pow(x, -1, MOD)
で逆元が計算できない -
math.factorial(x)
が までしか対応していない(!?)(内部実装)0\leqq x\leqq20 -
math.isqrt(x)
がない(大きな数では正確に平方根が計算できないことがある)
など。
後半のmathに関してはfrom python import math
でCPythonと同じライブラリを使うことはできますが、遅くなります。(後述)
ライブラリ
CPythonとは、標準で利用できるライブラリが異なります。
bisect
やcollections.Deque
、SortedList
(CPythonは標準で入ってない!)などは標準ライブラリとして入っていますが、
ACLはそのままimportして使うことができません。
(これはAtCoderのジャッジにインストールされているもの)
ちなみに、pipでインストールしたパッケージは、Codonの場合
from python import package_name
で使うことができます。
例:UnionFind
(インストールスクリプトより一部抜粋)
import sys
from python import atcoder.dsu as dsu
def main() -> None:
d = dsu.DSU(10)
d.merge(1, 2)
print(d.groups())
main()
しかし、このように実行すると(おそらく)CPythonの実行速度となり、
遅いのでおすすめしません。
組み込み関数
Codonだと使えない関数が多くあります。
特に影響がありそうなのはexit
・format
・frozenset
などでしょうか。
使えないものは代替しましょう。(exit()
ならsys.exit()
にするとか)
使用できるすべての関数
コメントアウトされているものは使えません。
エラー系などは除いています。
Exception
False
None
True
abs
# aiter
all
# anext
any
# ascii
bin
bool
# breakpoint
# bytearray
# bytes
# callable
chr
# classmethod
# compile
complex
# copyright
# credits
# delattr
dict
# dir
divmod
enumerate
# eval
# exec
# exit
filter
float
# format
# frozenset
getattr
# globals
hasattr
hash
# help
hex
id
input
int
isinstance
# issubclass
iter
len
# license
list
# locals
map
max
# memoryview
min
next
object
oct
open
ord
pow
print
# property
# quit
range
repr
reversed
round
set
setattr
slice
sorted
# staticmethod
str
sum
super
tuple
type
# vars
zip
実際に問題を解いてみた
Language Test 202505にある、言語のテスト用の問題を解いてみました。
提出したコードはすべてGithubにコミットしており、
main.py
はCPythonと同一のコードでACできたもの、main.codon
はCodon用にコードを修正してACしたものです。
AtCoder Beginners Selection
AtCoder Beginners Selection (初心者用の過去問10選)と同じ問題をすべて解きました。
結果としては、ほぼすべての問題においてCPythonと同じコードでACできました。
例:CPythonと同じように、こんな書き方もできちゃいます。
a, b = [int(x) for x in input().split()] # リスト内包表記で入力の受け取り
print("Even" if a * b % 2 == 0 else "Odd") # 三項演算子
N = int(input())
A = [int(x) for x in input().split()]
A.sort(reverse=True)
# ジェネレータの内包表記をsumにそのままぶち込む
print(sum(A[i] for i in range(N) if i % 2 == 0) - sum(A[i] for i in range(N) if i % 2 == 1))
N = int(input())
D = [int(input()) for x in range(N)]
# setもちゃんと使える
print(len(set(D)))
唯一同じコードでACできなかったのは、先述したようにexit()
が使えないところでした。
とはいってもこれについてはいくらでも代替の方法がありますが。
また、ABC086Cで試してみたのですが、リストで受け取った入力をtupleに変換するのはやはり面倒そうでした。
Plans = [tuple(int(x) for x in input().split()) for _ in range(N)]
# error: iterable must be a tuple, not 'List[str]'
inputのリストの長さを3に切り取ったり(input().split()[:3]
)もしてみましたが、結局エラー。
Plans = []
for _ in range(N):
txy = [int(x) for x in input().split()]
Plans.append((txy[0], txy[1], txy[2]))
最終的にこうすればtupleは使えましたが、listならCPythonと変わらずに使える中、
あえてtupleを使うメリットは薄そうだなと思いました。
CodonのtupleはCのstructに変換されるようなので、実行速度をもっと切り詰めたいならありなのかな?
(ABC086Cの場合、4msだけ短くなっていました。)
ABC385D - Santa Claus 2
Pythonが実行時間でギリギリになる問題です。(自分のコードはCPythonだとTLEでした)
この問題も、コードを変えずにCodonで動かせました。
# 二分探索のライブラリも問題なく使える!
from bisect import bisect_left, bisect_right
# (後略)
処理系 | 実行時間 |
---|---|
CPython | > 2000ms (TLE) |
PyPy | 1552 ms |
Codon | 666 ms |
CPythonと比べると少なくとも3倍以上、PyPyと比べても2.3倍程度高速化しました!!
PyPyでも定数倍が厳しいときの強力な解決手段になりそうです!
AtCoder Library Practice Contest(今後執筆予定)
ACLをpythonのライブラリ経由で使った実行速度と、ライブラリを直で貼った速度を比較します。
もうしばらくお待ちください。
おわりに
Codonの追加を受け、Pythonの「実行速度が遅い」問題が少しでも改善するといいなと思います。
自分はCodonがApache-2.0ライセンスになったのを見つけて提案したのですが、
その後のインストールスクリプトの作成はpunirunさんが作成してくださりました。
本当にありがとうございます。
最後まで読んでくださりありがとうございました。
この記事は、2025年9月時点での情報をもとにしています。
間違っている情報があったらDiscussionで教えていただけると嬉しいです。
Discussion
来週、10月7日(火)のAtCoder Daily Trainingから、先行でアップデートが実施されるそうです!