私が小さい頃、プログラミングは簡単でした。私の友人はコンピューターを持っていて、Basic と Assembly がありました。 Basic でプログラムを作成することもできますが、そのほうが簡単ですが、プログラムは遅くなります。または、アセンブリで何かを作成することもできますが、これはより困難ですが、プログラムの実行速度は大幅に速くなります。
これについての説明も簡単でした。 Basic はインタプリタでした。プログラムを実行するには、呼び出すたびにコードを調べて、1 行ずつ解釈する必要がありました。 「PRINT X」と表示されている場合、インタープリターは「X」という名前の変数を見つけ、印刷を行うルーチンを見つけ、見つかった変数に対して見つかったルーチンを呼び出す必要がありました。
組み立ては、まあ、組み立てでした。ある意味でプログラムも解釈しましたが、アセンブラを実行したときに1回だけです。その後、プログラムは解釈なしで実行可能になります。解釈を必要とするプログラムは、解釈を必要としないプログラムよりも遅く実行されます。もちろん、それらが同等のプログラムである場合。
そして、基本とアセンブリでは、通常はそうでした。 Basic は命令型言語であり、構造化プログラミングにはあまり適していません。 「関数」のように定番のものでさえ、組み込みの言語構造ではなく、「GOSUB ... RETURN」というパターンであり、アセンブリの「call ... ret」とほとんど同じです。
30年早送りします。言語はたくさんあります。コンピュータはどこにでもあります。プログラミングはもはや単純ではありません。 Python は解釈されて遅く、C++ はコンパイルされて高速であるというのが一般的な知識であるため、私の部門は、もともと Python で書かれた研究者のコードをパフォーマンスのために C++ で書き直すことで収入を得ています。しかし、どういうわけか、毎年、この書き直しはますます難しくなり、パフォーマンスを勝ち取ることはますます難しくなっています。何かが変化し、急速に変化します。しかし、常識は変わらないので、書き直しを続けています。
しかし今、私たちは自分のしていることを正当化するためだけに、狂ったようにすべてを最適化することを余儀なくされています。アルゴリズムが Python で入ってきて、C++ で同等に書き直すと、突然 3 倍遅くなります。それは... 私たちがここにいる目的ではありません。そのため、アルゴリズムを再設計して、約束したパフォーマンスの向上を実現しました。そして、ほとんどの場合、研究者はパフォーマンスをまったく気にせず、アルゴリズム的には簡単に達成できる成果を残しているため、これは機能します。
それでも、このビジネス全体が詐欺のように見えます。コードを再設計して高速化できるように、C++ でコードを書き直してコードを低速化しています。それでは、Python で直接再設計してみませんか?ああ!問題は、私たちは Python を知らないということです。 Python については、読んで理解するには十分ですが、Python で超高速のプログラムを作成するには十分ではありません。
それで、何を知る必要がありますか?
Python ライブラリのほとんどは、C または Fortran で記述されています。 NumPyコアは C で書かれています。パンダ- Cython および C; SciPy - Fortran、C、および部分的に C++ で。 C++、Rust、または Julia で書かれたものよりも遅くなる理由はありません。ただし、それらはより高速になる可能性があります。
当社では、クラウド サービスとデスクトップ アプリケーションの両方に対応しています。また、デスクトップ ユーザーは、お気に入りのアプリケーションの新しいバージョンが、明らかに理由もなくハードウェアで動作しなくなると、怒りを覚えます。そのため、デスクトップ ビルドのターゲットを古いままにします。ネハレム以前のように、本当に古い。こうすれば、誰も怒らず、誰も SSE3 を楽しむことができません。
もちろん、適切なターゲット用に構築された計算ライブラリは、通常、スーパースカラー機能が制限された汎用の 15 年前のコンピューター用に構築された同等のライブラリよりも高速です。
幸いなことに、クラウド向けにビルドしている場合、ターゲット ビルド プラットフォームを調達したマシンとまったく同じに設定できます。そうすれば、C++ ライブラリは Python ライブラリと同じ速度で実行されます。
正直に言うと、どちらの言語が速いかという議論全体はばかげています。言語はコンパイラやインタープリターではありません。言語そのものです。つまり、やりたいことをコンピューターに伝える方法を指定する一連の規則です。言語は単なる一連の規則、仕様です。何もありません。
解釈と編纂の違いは、前世紀のものです。最近では、 IGCC 、 PicoC 、またはCConsなどの C インタープリターがあり、Python コンパイラーがあります。 [PyPy] などの JIT コンパイラーや、 Codonなどの実行前にコンパイルする従来のコンパイラー (コードの一部のみをコンパイルする場合は、JIT 機能も備えています)。
Codon は、Rust、Julia、または Clang が構築されているのと同じインフラストラクチャである LLVM に基づいて構築されています。 Codon でビルドされたコードは、それらのいずれかでビルドされたのと同じパフォーマンス レベルで実行されます。 Python のガベージ コレクションや大規模なネイティブ データ型が原因でパフォーマンスが低下する可能性がありますが、100 倍または 10 倍についてはもう話していません。 LLVM はその魔法を行います。 Python コードをマシン コードに変換します。
ジャストインタイム コンパイルまたは JIT に関する神話もあります。通常の実行前にコンパイルする手法よりも優れていると言う人もいます。これは、常にユーザーが使用しているアーキテクチャ用にコンパイルし、最適に活用できるためです。ジャストインタイム コンパイルでもユーザーに負担がかかるコンパイル オーバーヘッドがまだあると言う人もいます。これにより、プログラムは実行とコンパイルの両方を同時に実行する必要があるため、プログラムの実行が遅くなります。
両方の神話の問題は、どちらも真実であり、どちらも役に立たないということです.はい、JIT は通常、ターゲット マシン用に明示的にバイナリをビルドしない限り、より優れたマシン コードにコンパイルされます。ちなみに、これはクラウドに展開するときにかなり頻繁に行われます。はい、ランタイムにはコンパイルのペナルティがありますが、ランタイムが月単位で測定されている場合は無視できます。これも、クラウドにデプロイする場合、前例のないことではありません.
したがって、長所と短所があります。重要なのは、Python (具体的には Codon) が compile-before-you-run モードと JIT モードの両方をサポートしているため、ニーズに最も適したものを選択できることです。 Clang などの従来のコンパイラには、JIT オプションがありません。
JIT といえば、 Numbaはおそらく、超高速 Python プログラミングの世界で最も革新的なテクノロジです。これはコンパイラですが、プログラム全体ではなく、選択したカーネルのみを対象としています。もちろん、何をどのプラットフォーム用にコンパイルするかを選択できます。このセットアップでは、コードの一部を CPU で実行し、その他のコードをGPGPUで実行できます。
技術的には、Google のTPUや Lightmatters のフォトニック アクセラレータなど、他の特殊なデバイス用のバックエンドを作成できます。そのようなバックエンドはまだありません。彼らは代わりに独自のライブラリを展開することにしました。しかし、症状としては、Python でフォトニック コンピューターのインターフェイスを提供することも選択しているため、Pytorch、Tensorflow、または ONNX とシームレスに対話できます。
したがって、ライトマターはまだありません。しかし、NVidiaは.彼らは Numba 用の CUDA バックエンドを提供しており、Python でカーネルを記述し、NVidia ハードウェアで最大限の効率で実行できるようになりました。 C++ にはそれがありません。ただし、もちろん、 NVidiaに由来する CU 方言があり、これはまさにこの問題のために C++ を拡張します。 Python では、言語自体を拡張する必要はありません。 Numba は JIT カーネル コンパイラとして機能するため、ライブラリにパッチを適用するだけでバックエンドを追加できます。
つまり、カーネル モデルは異種コンピューティングを対象としています。さまざまなデバイスでコードを実行できます。これはそれ自体が優れています。しかし、異質性には、あなたが考えもしなかった別の側面があります。カーネル モデルを使用すると、必ずしもハードウェア デバイスではなく、異なる計算コンテキストに対して異なるカーネルをターゲットにすることができます。これは、1 つのカーネルを速くしたいが特に正確ではない場合、「-fast-math」オプションを使用してビルドできることを意味します。しかし、他のコンテキストで、そのカーネルを高速ではなく正確にしたい場合は、トレードオフなしでまったく同じコードを再構築できます。
これは、翻訳単位の途中でコンパイル オプションを変更できない従来のコンパイラでは実現が難しいことです。カーネル モデルでは、すべてのカーネルが独自の翻訳単位です。
Python は遅くありません。どちらも高速ではありません。それは単なる言語であり、一連のルールとキーワードです。しかし、これらのルールやキーワードに慣れてしまった人はたくさんいます。彼らは Python で快適に書くことができ、Python を自分たちにとってより良いものにすることに興味を持っています。
このユーザー ベースは、Lightmatter やそのフォトニック コンピューターなどの革新的なテクノロジーを備えた新興企業と、NVidia などのハイ パフォーマンス コンピューティングの専門知識を何十年も持つ老舗企業の両方を引き付けるのに十分な大きさです。これらすべての人々は、Python をより良いものにするために多大な投資を行っています... もちろん、言語ではなく、環境です。超高速のプログラムを書く環境は、遅い使い捨てのプログラムを書くよりもわずかに難しいだけです。
全体として、彼らは大きな進歩を遂げています。 Python は年々高速化しています。この時点で、できればフォトニック コンピューターのことは忘れてください。Python で記述されたプログラムは、多くの場合、Julia、C++、または Rust で記述されたプログラムと同等に実行されます。しかし、Python はそれだけではありません。従来のコンパイラよりも使いやすくなっています。
数年後には、Python コンパイラー (PyPy、Numba、またはまったく新しいもの) が、 SpiralやHerbieの技術を借用して、従来のコンパイラーには到底及ばないほど効率的にコードを生成するようになるでしょう。結局のところ、Python で新しい JIT バックエンドを作成することは、LLVM インフラストラクチャ全体を再考するよりもはるかに簡単です。