for Startups Tech blog

for Starupsのテックブログです

Mojoってみた

初めまして、2023年2月にフォースタートアップス株式会社に入社したモジョモジョドレミことモジョリアンの江種(@hairinhi)と申します。現在、主にRuby on Railsで作られている社内向けプロダクト「タレントエージェンシー支援システム(SFA/CRM)」の開発、運用を担当しております。

はじめに

Mojoとは、Python構文の長所とシステムプログラミングおよびメタプログラミングを組み合わせることによって生み出された、研究と運用の間のギャップを埋める新しいプログラミング言語です。公式ドキュメントには、Mojoを使用すると、C言語よりも高速でPythonのエコシステムとシームレスに相互運用できる移植可能なコードを作成できると書かれています。

また、公式サイトではPythonよりも最大35000倍速く計算できると謳われています。Pythonのエコシステムを引き継ぎつつ高速に実行できるということで、AI分野での活躍が特に期待できますね。

今回はこのMojoPythonと比較して、本当に35000倍速く計算できるのか確認してみたいと思います。

Mojoを試すには

現在(2023年7月時点)、Mojoは開発元のModular社が用意しているJupyterHub環境にあるMojo PlayGroundでしか試すことができません。ここでは、利用できるようになるための手順を簡単にご紹介します。

1. ユーザー登録

まず、こちらのサインアップページからユーザー登録を行なってください。

2. 招待メールを受け取る

ユーザー登録を行なって、数日待つと登録したメールアドレスに招待メールが届きます。早ければ、登録したその日に招待メールが来ることもあります。

3. Mojo Playgroundにアクセスする

招待メールにある「Access Mojo Playground」のリンクにアクセスすると、JupyterHub環境が起動して、Mojoを利用できるようになります。

性能比較をしてみました

このMojoPythonよりもどのぐらい高速なのか気になったので、3つの簡単なアルゴリズムで性能比較をしてみました。

FizzBuzz問題
皆さんお馴染みのFizzBuzz問題で検証してみました。1 ~ 100までの数で試しています。

フィボナッチ数列
フィボナッチ数列もご存じの方が多いと思います。スクラム開発で各タスクにストーリーポイントを割り振る時にも使われますね。今回は30番目の値を求めてみます。

アッカーマン関数
アッカーマン関数とは計算可能であるが原始再帰的ではない、well-definedTotal Functionの最も単純な関数であり、さらに1900年代初期に信じられていた「計算可能な関数はすべて原始再帰的でもある」という考えに対する反例でもあります。この関数は指数関数や多重指数関数よりも急速に増大していく関数であることが知られています。今回は第一引数を3、第二引数を12にして試してみました。

ご注意!
今回、MojoについてはMojo Playgroundで、Pythonについては私が普段業務で使用している以下のようなスペックのマシンで試しています。

MacBook Pro 2021
チップ: Apple M1 Max
メモリ: 64GB
macOS: Ventura 13.0
Pythonのバージョン: 3.11.1

よって、実行環境がMojoPythonで違うので厳密な比較にはなっておりません。また、処理時間の計測にPythonではtimeitモジュールを使用し、Mojoでは処理開始時刻と終了時刻の差を計算しています。

あくまで参考程度にご覧ください。

Python

FizzBuzz問題

from timeit import timeit

def fizz_buzz(n):
    if n % 15 == 0:
        print("FizzBuzz")
    elif n % 3 == 0:
        print("Fizz")
    elif n % 5 == 0:
        print("Buzz")
    else:
        print(n)

def benchmark():
    for i in range(1, 101):
        fizz_buzz(i)

result = timeit(lambda: benchmark(), number = 1)
print(result * 1000000000, "[ナノ秒]")

結果

1
2
Fizz
4
Buzz
Fizz
〜〜途中省略〜〜
FizzBuzz
91
92
Fizz
94
Buzz
Fizz
97
98
Fizz
Buzz
136792.19409823418 [ナノ秒]

フィボナッチ数列

from timeit import timeit

def fib(n):
    if n < 2:
        return n
    else:
        return fib(n-1) + fib(n-2)

def benchmark():
    print(fib(30))

result = timeit(lambda: benchmark(), number = 1)
print(result * 1000000000, "[ナノ秒]")

結果

832040
98048625.04824996 [ナノ秒]

アッカーマン関数

import sys
from timeit import timeit

# Pythonの場合再帰回数の上限を上げておく必要があります
sys.setrecursionlimit(200000000)

def ack(m, n):
    if m == 0:
        return n + 1
    elif n == 0:
        return ack(m - 1, 1)
    else:
        return ack(m - 1, ack(m, n - 1))

def benchmark():
    print(ack(3, 12))

result = timeit(lambda: benchmark(), number = 1)
print(result * 1000000000, "[ナノ秒]")

結果

32765
45427333666.943016 [ナノ秒]

Mojo

FizzBuzz問題

from Time import now

fn fizz_buzz(n: Int):
    if n % 15 == 0:
        print("FizzBuzz")
    elif n % 3 == 0:
        print("Fizz")
    elif n % 5 == 0:
        print("Buzz")
    else:
        print(n)

start = now()
for i in range(1,101):
    fizz_buzz(i)
end = now()

print(end - start, '[ナノ秒]')

結果

1
2
Fizz
4
Buzz
Fizz
〜〜途中省略〜〜
FizzBuzz
91
92
Fizz
94
Buzz
Fizz
97
98
Fizz
Buzz
362569 [ナノ秒]

フィボナッチ数列

from Time import now

fn fib(n: Int) -> Int:
    if n < 2:
        return n
    else:
        return fib(n-1) + fib(n-2)

start = now()
print(fib(30))
end = now()

print(end - start, "[ナノ秒]")

結果

832040
2563558 [ナノ秒]

アッカーマン関数

from Time import now

def ack(m: Int, n: Int) -> Int:
    if m == 0:
        return n + 1
    elif n == 0:
        return ack(m - 1, 1)
    else:
        return ack(m - 1, ack(m, n - 1))

start = now()
print(ack(3, 12))
end = now()

print(end - start, "[ナノ秒]")

結果

32765
4242469743 [ナノ秒]

比較

実行結果を表にまとめてみました。(単位はナノ秒)

アルゴリズム Pythonの結果 Mojoの結果 比較
FizzBuzz問題 136792.19409823418 362569 Pythonのほうが約2.6倍速い
フィボナッチ数列 98048625.04824996 2563558 Mojoのほうが約38倍速い
アッカーマン関数 45427333666.943016 4242469743 Mojoのほうが約10倍速い

FizzBuzz問題については、意外にもPythonのほうが速かったです。これはMojoの標準出力がボトルネックになっていると思われます。それ以外については、期待通りMojoのほうが速い結果となりました。

考察

公式サイトにあるようにMojoのほうが 35000倍速い! という結果にはなりませんでした。そこで、もう一度公式サイトを見ると、比較表の下に注意書きでInstance AWS r7iz.metal-16xl Intel Xeonと書かれていました。AWSのEC2インスタンスの中でR7izインスタンスというと、全コア最大ターボ周波数が3.9GHzの第4世代Intel Xeonスケーラブルプロセッサを搭載した初のEC2インスタンスとして知られています。またR7izインスタンスは、最大1,024GiBのメモリと最大128のvCPUを搭載しているので、金融・保険業界やデータ分析など高いパフォーマンスが求められる環境において最大限そのパフォーマンスを発揮することができます。

このことから言えるのは、Mojoは実行環境が良くなればなるほど、その真価を発揮できる可能性があるということです。今回の検証ではJupyterHub環境とMacBook Proを使用しました。「Pythonよりは速い」という程度の結果を得ることができましたが、一方で「まだまだ俺の力はこんなものじゃない」とMojoが語りかけているようにも思えました。

まとめ

FizzBuzz問題の結果は意外でしたが、概ねMojoのほうが速いということが分かりました。普段の業務では、AI関連の業務に関わることは少ないですが、個人的に非常に興味がある分野でもあります。これからもMojoについてはキャッチアップしていきたいと思います。

採用

最後に採用情報です。 当社では、まだまだ採用募集中です。ぜひ一緒にMojoについて語り合いましょう!ご興味ありましたらぜひ一度カジュアルにお話できたらと思います。 採用ページはこちら

参考資料

https://zenn.dev/turing_motors/articles/e23973714c3ecf
https://www.kurims.kyoto-u.ac.jp/~cs/cs2011_terui.pdf