web-dev-qa-db-ja.com

Pythonのメモリ制限を増やしていますか?

現在、非常に長い辞書(DNA文字列の比較に使用)を作成する関数を使用しており、MemoryErrorが発生する場合があります。 Pythonより多くのデータを一度に処理できるように、より多くのメモリを割り当てる方法はありますか?

11
Maor

Pythonには、システムの制限であるMomeoryErrorがありますRAM util resourceパッケージで手動で定義したユーティリティ。

slotsを使用してクラスを定義すると、pythonインタープリターは、クラスの属性/メンバーが修正されたことを認識します。また、メモリを大幅に節約することができます。

pythonインタープリターは__slot__を使用することにより、dictの作成を減らすことができます。これにより、インタープリターは内部でdictを作成せず、同じ変数を再利用します。

pythonプロセスによって消費されるメモリが時間とともに増大し続ける場合、これは次の組み合わせのようです:

  • PythonのCメモリアロケータの動作方法。これは、メモリチャンク全体が使用されていない限り、割り当てが 'free'を呼び出せないため、本質的にメモリの断片化です。作成して使用するオブジェクトに。
  • 多数の小さな文字列を使用してデータを比較します。内部で使用されるインターニングと呼ばれるプロセスが複数の小さな文字列を作成すると、インタープリターに負荷がかかります。

最善の方法は、ワーカースレッドまたはシングルスレッドプールを作成して作業を行い、ワーカー/キルを無効にして、ワーカースレッドでアタッチ/使用されているリソースを解放することです。

以下のコードはシングルスレッドワーカーを作成します:

__slot__ = ('dna1','dna2','lock','errorResultMap')
lock = threading.Lock()
errorResultMap = []
def process_dna_compare(dna1, dna2):
    with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
        futures = {executor.submit(getDnaDict, lock, dna_key): dna_key for dna_key in dna1}
    '''max_workers=1 will create single threadpool'''
    dna_differences_map={}
    count = 0
    dna_processed = False;
    for future in concurrent.futures.as_completed(futures):
        result_dict = future.result()
        if result_dict :
            count += 1
            '''Do your processing XYZ here'''
    logger.info('Total dna keys processed ' + str(count))

def getDnaDict(lock,dna_key):
    '''process dna_key here and return item'''
    try:
        dataItem = item[0]
        return dataItem
    except:
        lock.acquire()
        errorResultMap.append({'dna_key_1': '', 'dna_key_2': dna_key_2, 'dna_key_3': dna_key_3,
                          'dna_key_4': 'No data for dna found'})
        lock.release()
        logger.error('Error in processing dna :'+ dna_key)
    pass

if __name__ == "__main__":
    dna1 = '''get data for dna1'''
    dna2 = '''get data for dna2'''
    process_dna_compare(dna1,dna2)
    if errorResultMap != []:
       ''' print or write to file the errorResultMap'''

以下のコードは、メモリ使用量を理解するのに役立ちます:

import objgraph
import random
import inspect

class Dna(object):
    def __init__(self):
        self.val = None
    def __str__(self):
        return "dna – val: {0}".format(self.val)

def f():
    l = []
    for i in range(3):
        dna = Dna()
        #print “id of dna: {0}”.format(id(dna))
        #print “dna is: {0}”.format(dna)
        l.append(dna)
    return l

def main():
    d = {}
    l = f()
    d['k'] = l
    print("list l has {0} objects of type Dna()".format(len(l)))
    objgraph.show_most_common_types()
    objgraph.show_backrefs(random.choice(objgraph.by_type('Dna')),
    filename="dna_refs.png")

    objgraph.show_refs(d, filename='myDna-image.png')

if __name__ == "__main__":
    main()

メモリ使用量の出力:

list l has 3 objects of type Dna()
function                   2021
wrapper_descriptor         1072
dict                       998
method_descriptor          778
builtin_function_or_method 759
Tuple                      667
weakref                    577
getset_descriptor          396
member_descriptor          296
type                       180

スロットの詳細については、次をご覧ください。 https://elfsternberg.com/2009/07/06/python-what-the-hell-is-a-slot/

0
Mandy