マルチコアPython:タフで、価値があり、到達可能な目標

Pythonの優れた便利な機能のすべてについて、1つの目標は達成できません。CPythonリファレンスインタープリターで実行され、複数のCPUコアを並行して使用するPythonアプリです。

これは、特にすべての回避策が不器用であるため、Pythonの最大の障害の1つでした。特にプロセッサのコア数が増え続けているため、この問題の長期的な解決策を見つける緊急性が高まっています(Intelの24コアの巨人を参照)。

すべてのための1つのロック

実際、Pythonアプリケーションでスレッドを使用することは可能です-それらの多くはすでに使用しています。何 でないCPythonのは、各スレッドが実行すると、マルチスレッドアプリケーションを実行するための可能なことである並列に異なるコア上。CPythonの内部メモリ管理はスレッドセーフではないため、インタープリターは一度に1つのスレッドのみを実行し、必要に応じてスレッドを切り替えて、グローバル状態へのアクセスを制御します。

このロックメカニズムであるグローバルインタープリターロック(GIL)は、CPythonがスレッドを並列に実行できない最大の理由です。いくつかの問題を緩和する要素があります。たとえば、ディスクやネットワークの読み取りなどのI / O操作はGILに拘束されないため、独自のスレッドで自由に実行できます。しかし、マルチスレッドとCPUバウンドの両方が問題です。

Pythonプログラマーにとって、これは、外部ライブラリの使用を除いて、複数のコアに分散することで恩恵を受ける重い計算タスクがうまく実行されないことを意味します。Pythonでの作業の利便性には大きなパフォーマンスコストが伴いますが、GoogleのGoのような高速で同様に便利な言語が前面に出てくるにつれて、飲み込むのが難しくなっています。

ロックを選ぶ

時間の経過とともに、GILの制限を改善する(ただし、排除するわけではない)多くのオプションが登場しました。標準的な戦術の1つは、CPythonの複数のインスタンスを起動し、それらの間でコンテキストと状態を共有することです。各インスタンスは、別々のプロセスで互いに独立して実行されます。ただし、Jeff Knuppが説明するように、並列実行によって得られるメリットは、状態を共有するために必要な労力によって失われる可能性があるため、この手法は、結果を時間の経過とともにプールする長時間実行の操作に最適です。

C拡張機能はGILに拘束されないため、速度を必要とするPython用の多くのライブラリ(math-and-statsライブラリNumpyなど)を複数のコアで実行できます。ただし、CPython自体の制限は残っています。GILを回避する最善の方法がCを使用することである場合、それはより多くのプログラマーをPythonからCに向かわせるでしょう。

JITを介してコードをコンパイルするPythonバージョンであるPyPyは、GILを削除しませんが、コードをより高速に実行するだけでそれを補います。いくつかの点で、これは悪い代用​​ではありません。速度がマルチスレッドに注目している主な理由である場合、PyPyはマルチスレッドの複雑さなしに速度を提供できる可能性があります。

最後に、GIL自体がPython 3でいくらか作り直され、スレッド切り替えハンドラーが改善されました。しかし、その根底にあるすべての仮定(および制限)は残っています。まだGILがあり、それはまだ手続きを保留しています。

GILはありませんか?問題ない

これらすべてにもかかわらず、既存のアプリケーションと互換性のあるGILのないPythonの探求は続いています。 Pythonの他の実装は、GILを完全に廃止しましたが、コストがかかります。たとえば、JythonはJVM上で実行され、GILの代わりにJVMのオブジェクト追跡システムを使用します。 IronPythonは、MicrosoftのCLRを介して同じアプローチを取ります。ただし、どちらもパフォーマンスに一貫性がなく、CPythonよりも実行速度がはるかに遅い場合があります。また、外部Cコードと簡単にインターフェースできないため、既存のPythonアプリケーションの多くは機能しません。

ContinuumAnalyticsのTrentNelsonによって作成されたプロジェクトであるPyParallelは、「複数のCPUコアを最適に活用するように設計されたPython3の実験的な概念実証フォーク」です。 GILは削除されませんが、asyncモジュールを置き換えることでその影響が改善されるためasync、並列処理に使用するアプリ (WebサーバーのようなマルチスレッドI / Oなど)が最もメリットがあります。プロジェクトは数か月間休止していますが、そのドキュメントには、開発者が時間をかけて正しく処理できると記載されているため、最終的にCPythonに含めることができます。「進行中の場合は、ゆっくりと安定しても問題はありません。正しい方向に」

PyPyの作成者による長期にわたるプロジェクトの1つは、「ソフトウェアトランザクショナルメモリ」(PyPy-STM)と呼ばれる手法を使用するPythonのバージョンです。PyPyの作成者によると、この利点は、「既存の非マルチスレッドプログラムに微調整を加えて、複数のコアを使用できるようにすることができる」ということです。

PyPy-STMは魔法のように聞こえますが、2つの欠点があります。まず、現在Python 2.xのみをサポートしている進行中の作業であり、次に、シングルコアで実行されているアプリケーションのパフォーマンスが低下します。Pythonの作成者であるGuidovan RossumがCPythonからGILを削除しようとする際に引用した規定のひとつは、その置き換えによってシングルコアのシングルスレッドアプリケーションのパフォーマンスが低下しないことであるため、このような修正はCPythonに反映されません。現在の状態です。

急いで待って

Pythonのコア開発者であるLarryHastingsは、PyCon 2016で、GILを削除する方法についていくつかの見解を共有しました。ヘイスティングスは、GILを削除しようとしたことを記録しました。そうすることで、GILを持たないバージョンのPythonになりましたが、キャッシュミスが頻繁に発生するため、実行速度が非常に遅くなりました。

ヘイスティングスの要約によると、GILを失う可能性がありますが、一度に1つのスレッドのみがグローバルオブジェクトを変更することを保証する方法が必要です。たとえば、インタープリターの専用スレッドでそのような状態の変更を処理します。

長期的な朗報の1つは、CPythonがGILを排除した場合、その言語を使用する開発者はすでにマルチスレッドを活用する準備が整っているということです。Python 3.5のキューやasync/awaitキーワードなど、Pythonの構文に組み込まれた多くの変更により、コア間でタスクを高レベルで簡単に割り当てることができます。

それでも、Python GILを少なくするために必要な作業量は、PyPy-STMのような別の実装で最初に表示されることを保証します。GILのないシステムを試したい人は、そのようなサードパーティの努力によってそれを行うことができますが、元のCPythonは今のところ手つかずのままである可​​能性があります。待ち時間がそれほど長くないことを願っています。