しばらく前に、Python で IRC 用のマルコフ連鎖テキスト ジェネレーターを作成しました。1、2 か月実行すると、VPS の空きメモリがすべて消費され、データを消去して最初からやり直す必要がありました。今、私はそれを書き直しており、できるだけエレガントにメモリの問題に取り組みたいと思っています。
切り捨てておく必要があるデータは、通常、文字列を文字列のリストにマップする辞書です。より具体的には、メッセージ内の各単語は、可能なすべての後続の単語にマップされます。これはまだ単純化しすぎていますが、問題を文脈化するには十分です。
現在、私が取り組んでいるソリューションには、データの「バケット」の管理が含まれます。各バケットの見かけのサイズを追跡し、特定のサイズに達するとバケットを「アーカイブ」して新しいバケットに移動します。バケットが 5 つほど経過すると、新しいバケットが作成されるたびに最も古い「アーカイブ済み」バケットが削除されます。作成した。これには、単純さという利点があります。バケット全体を削除しても、各メッセージの単語がすべて同じバケットに移動するため、行き止まりや到達不能な単語が作成されることはありません。
問題は、「各バケットの見かけのサイズを追跡する」ことは、口で言うほど簡単ではないということです。
最初に を使用してみましたが、メモリ内のオブジェクトの実際のsys.getsizeof
サイズを決定するのに実用的ではないことがすぐにわかりました。グッピー/ヒーピー/その他のさまざまなメモリ使用モジュールも調べましたが、探していることを実行しているようには見えません(つまり、単一のオブジェクトのベンチマーク)。現在、下位レベルのpsutilモジュールを試しています。以下は、アプリケーションの現在の状態からの抜粋です。
class Markov(object):
# (constants declared here)
def __init__(self):
self.proc = psutil.Process(os.getpid())
self.buckets = []
self._newbucket()
def _newbucket(self):
self.buckets.append(copy.deepcopy(self.EMPTY_BUCKET))
def _checkmemory(f):
def checkmemory(self):
# Check memory usage of the process and the entire system
if (self.proc.get_memory_percent() > self.MAX_MEMORY
or psutil.virtual_memory().percent > self.MAX_TOTAL_MEMORY):
self.buckets.pop(0)
# If we just removed the last bucket, add a new one
if not self.buckets:
self._newbucket()
return f()
return checkmemory
@_checkmemory
def process(self, msg):
# generally, this adds the words in msg to self.buckets[-1]
@_checkmemory
def generate(self, keywords):
# generally, this uses the words in all the buckets to create a sentence
ここでの問題は、これがバケットのみを期限切れにすることです。現在のバケットを「アーカイブ」するタイミングがわかりません。Python のオーバーヘッド メモリによって、self.MAX_MEMORY
. 言うまでもなく、このMarkov
クラスは実際には、ヘッドレス IRC クライアントによって管理される多くの「プラグイン」の 1 つです (簡潔にするために省略した別の詳細)。そのため、オーバーヘッドは存在するだけでなく、予測不可能です。
要するに、単一の Python オブジェクトを正確にベンチマークする方法はありますか? あるいは、バケットベースのソリューションよりも古いデータを「期限切れ」にするためのより良い方法を考えられるなら、私はすべて耳にします。