💨

【Python高速化】AtCoderでCodonが使えるようになるぞー!

に公開
1

今回(2024-25年度)の言語アップデートで、Codonが使えるようになります!
10月下旬ごろからコンテストで利用可能になる見込みです。
それに向けて、Codonを使うメリット・注意点などをまとめました。

追加される予定のジャッジは、Language Test 202505から試すことができます。

Codonとは?

https://docs.exaloop.io/
機械語にコンパイルできる、高性能なPythonの実装です。
Pythonの書き心地を維持しながら、理論上はC++と同等の速度を出せます!
通常使われているPython(CPython)と比べて10~100倍の高速化が期待できるそうです。

セットアップ・使い方

https://docs.exaloop.io/start/install/

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の共有ライブラリのパスを調べる必要があります。
詳しくは公式ドキュメントを見てください。
https://docs.exaloop.io/integrations/python/python-from-codon/

自分の場合(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のように計算が扱われるものがあります。

後半のmathに関してはfrom python import mathでCPythonと同じライブラリを使うことはできますが、遅くなります。(後述)

ライブラリ

CPythonとは、標準で利用できるライブラリが異なります。
bisectcollections.DequeSortedList(CPythonは標準で入ってない!)などは標準ライブラリとして入っていますが、
ACLはそのままimportして使うことができません。

https://github.com/not522/ac-library-python
Githubなどから、コードを直接コピペしてくるのがおすすめです。
(これは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だと使えない関数が多くあります。
特に影響がありそうなのはexitformatfrozensetなどでしょうか。
使えないものは代替しましょう。(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と同じように、こんな書き方もできちゃいます。

abc086a.py
a, b = [int(x) for x in input().split()]  # リスト内包表記で入力の受け取り
print("Even" if a * b % 2 == 0 else "Odd")  # 三項演算子
abc088b.py
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))
abc085b.py
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])もしてみましたが、結局エラー。

abc086c.codon
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で動かせました。

abc385d.py
# 二分探索のライブラリも問題なく使える!
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