31

私は、CPython が舞台裏でどのように実装されているかを学ぼうとしています。Python がハイレベルであることは素晴らしいことですが、ブラック ボックスのように扱うのは好きではありません。

それを念頭に置いて、タプルはどのように実装されますか? ソース (tupleobject.c)を見てきましたが、頭を悩ませています。

私はそれを見てPyTuple_MAXSAVESIZE = 20PyTuple_MAXFREELIST = 2000保存と「フリーリスト」とは何ですか? (長さ 20/21 または 2000/2001 のタプル間にパフォーマンスの違いはありますか? 最大タプル長を強制するものは何ですか?)

4

2 に答える 2

39

注意点として、この回答のすべては、リンクした実装を調べて収集したものに基づいています。

タプルの標準実装は単純に配列のようです。ただし、処理を高速化するための最適化が数多く行われています。

まず、空のタプルを作成しようとすると、CPython は代わりに空のタプルを表す標準オブジェクトを返します。その結果、単一のオブジェクトを割り当てるだけの一連の割り当てを節約できます。

次に、多数の小さなオブジェクトの割り当てを避けるために、CPython は多くの小さなリストのメモリをリサイクルします。PyTuple_MAXSAVESIZEこの長さより短いすべてのタプルがスペースを再利用できるように、固定定数 ( ) があります。この定数よりも短い長さのオブジェクトが割り当て解除されるたびに、それに関連付けられたメモリが解放されず、代わりにそのサイズに基づいて「空きリスト」(次の段落で詳しく説明します) に格納される可能性があります。 . そうすれば、サイズ n のタプルを割り当てる必要があり、1 つが以前に割り当てられて使用されなくなった場合、CPython は古い配列をリサイクルできます。

フリー リスト自体は、PyTuple_MAXSAVESIZE未使用のタプルへのポインターを格納するサイズの配列として実装されます。配列の n 番目の要素は、NULL (サイズ n の余分なタプルが利用できない場合) またはサイズ n の再利用されたタプルのいずれかを指します。再利用できるサイズ n の複数の異なるタプルがある場合、各タプルの 0 番目のエントリが再利用できる次のタプルを指すようにすることで、リンク リストのようなものに連鎖されます。(これまでに割り当てられた長さゼロのタプルは 1 つしかないため、存在しないゼロ番目の要素を読み取るリスクはありません)。このようにして、アロケータは再利用のために各サイズのいくつかのタプルを格納できます。これがメモリを使いすぎないようにするために、2 番目の定数があります。PyTuple_MAXFREELISTバケット内のこれらのリンクされたリストの最大長を制御します。PyTuple_MAXSAVESIZEこの上限を超えないように、指定された各長さのタプルのリンクされたリストの長さを格納する長さの二次配列があります。

全体として、これは非常に巧妙な実装です。

于 2013-01-03T09:14:26.947 に答える
38

通常の操作の過程で、Python は多数の小さなタプルを作成および破棄するため、Python はその目的のために小さなタプルの内部キャッシュを保持します。これにより、多くのメモリ割り当てと割り当て解除のチャーンを削減できます。同じ理由で、-5 から 255 までの小さい整数がインターンされます (シングルトンにされます)。

PyTuple_MAXSAVESIZE定義は、この最適化の対象となるタプルの最大サイズを制御し、定義PyTuple_MAXFREELISTは、これらのタプルのうちのいくつをメモリ内に保持するかを制御します。長さ < のタプルが破棄されると、Python が新しい小さなタプルを作成するときに再利用できるようにPyTuple_MAXSAVESIZE( で) まだ 1 つの余地があれば、フリー リストに追加されます ( で)。tupledeallocPyTuple_New

Python は、これらをどのように格納するかについて少し巧妙です。長さ > 0 のタプルごとに、キャッシュされた各タプルの最初の要素を再利用して、タプルを連鎖さPyTuple_MAXFREELISTせてリンク リストにします。したがって、free_list配列内の各要素は Python タプル オブジェクトのリンク リストであり、そのようなリンク リスト内のすべてのタプルは同じサイズです。唯一の例外は空のタプル (長さ 0) です。これらのうち 1 つだけが必要であり、それはシングルトンです。

したがって、そうです、長さを超えるタプルの場合、PyTuple_MAXSAVESIZEpython は新しい C 構造体に個別にメモリを割り当てる必要があることが保証されており、そのようなタプルを頻繁に作成および破棄すると、パフォーマンスに影響を与える可能性があります。

Python C の内部構造を理解したい場合は、Python C APIを学習することをお勧めします。Python が C でオブジェクト、関数、およびメソッドを定義するために使用するさまざまな構造を理解しやすくなります。

于 2013-01-03T09:12:21.887 に答える