2017-12-11 6 views
-2

私は1年間書いてきた大規模な30kラインプログラムを持っています。基本的には、複数のソースから正規化されていないデータと標準化されていないデータを収集し、ソースを標準化した後にすべてを照合します。私の中毒をPython辞書に切り込む方法

ほとんどのものは順序付き辞書で書いています。これにより、列の順序、名前、可変性を保つことができ、コードの混乱の中で値を割り当て/固定することができるため、処理が容易になりました。

しかし、私は現在、これらすべての辞書からRAMを使い果たしています。私は以来、namedtuplesへの切り替えがこれを修正することを学んだが、唯一の問題はこれらは変更可能ではないことで、変換を行う際に1つの問題が生じることです。

私はクラスを使用して不変性を排除することができると思いますが、RAM節約は同じになるでしょうか?もう一つの選択肢は、値を変更する必要があるたびに(つまり、NewTup = Tup(oldTup.odj1、oldTup.odj2、 "something new"))名前付きタプルを使用して新しい名前付きトゥープルに再割り当てすることです。

最後の行は私の入力ファイルはディスク(大量のデータ)の約6GBです。私はこのデータを16GB RAMのサーバで処理することを余儀なくされています私はもともとこれらのさまざまなI/Oデータセットのすべての行を辞書でプログラミングしていましたが、これはあまりにも多くのRAMを食べています...しかし、可変性と名前付き参照は高速開発で大きな助けとなりました私は辞書に加えて、アプリケーション全体をタプルの不変な性質に書き換えることなく、他のオブジェクトのコスト節約を利用できるようにしました。

サンプルコードは:

for tan_programs_row in f_tan_programs: 
    #stats not included due to urgent need 
    tan_id = tan_programs_row["Computer ID"].strip() #The Tanium ID by which to reference all other tanium files (i.e. primary key) 
    if("NO RESULT" not in tan_id.upper()): 
     tan_programs_name = tan_programs_row["Name"].strip() #The Program Name 
     tan_programs_publisher = tan_programs_row["Publisher"].strip() #The Program Vendor 
     tan_programs_version = tan_programs_row["Version"].strip() #The Program Vendor 

     try: 
      unnorm_tan_dict[tan_id] #test the key, if non-existent go to exception 
     except KeyError: 
      #form the item since it doesn't exist yet 
      unnorm_tan_dict[tan_id] = { 
       "Tanium ID": tan_id, 
       "Computer Name": "INDETERMINATE", 
       "Operating System": "INDETERMINATE", 
       "Operating System Build Number": "INDETERMINATE", 
       "Service Pack": "INDETERMINATE", 
       "Country Code": "INDETERMINATE", 
       "Manufacturer": "INDETERMINATE", 
       "Model": "INDETERMINATE", 
       "Serial": "INDETERMINATE" 
      } 
     unnorm_tan_prog_list.append(rows.TanRawProg._make([tan_id, tan_programs_name, tan_programs_publisher, tan_programs_version])) 

for tan_processes_row in f_tan_processes: 
    #stats not included due to urgent need 
    tan_id = tan_processes_row["Computer ID"].strip() #The Tanium ID by which to reference all other tanium files (i.e. primary key) 
    if("NO RESULT" not in tan_id.upper()): 
     tan_process_name = tan_processes_row["Running Processes"].strip() #The Program Name 
     try: 
      unnorm_tan_dict[tan_id] #test the key, if non-existent go to exception 
     except KeyError: 
      #form the item since it doesn't exist yet 
      unnorm_tan_dict[tan_id] = { 
       "Tanium ID": tan_id, 
       "Computer Name": "INDETERMINATE", 
       "Operating System": "INDETERMINATE", 
       "Operating System Build Number": "INDETERMINATE", 
       "Service Pack": "INDETERMINATE", 
       "Country Code": "INDETERMINATE", 
       "Manufacturer": "INDETERMINATE", 
       "Model": "INDETERMINATE", 
       "Serial": "INDETERMINATE" 
      } 
     unnorm_tan_proc_list.append(rows.TanRawProc._make([tan_id, tan_process_name])) 

*その後、これらの値には、多くの場合、他のデータセットを持ち込むことによって変更されています。

+0

dictsメモリの使用量を減らすと、これまでのところより多くのデータが追加されたり、同じサーバー上にメモリを摂取している別のプロセスがあり、メモリの問題が再び発生します。本当に問題を解決したいのであれば、大量のデータをRAMにロードする必要のないソリューションが必要です(適切なデータベース - より強固な関係かどうかは、ソリューションの一部であるかもしれません)。 –

答えて

2

はちょうどあなた自身のクラスを作成し、最小限にメモリフットプリントを維持するために__slots__を使用します。

class UnnormTan(object): 
    __slots__ = ('tan_id', 'computer_name', ...) 
    def __init__(self, tan_id, computer_name="INDETERMINATE", ...): 
     self.tan_id = tan_id 
     self.computer_name = computer_name 
     # ... 

このおそらく少し冗長を得ることができ、あなたはこれらのような辞書のキーを使用する必要がある場合もっとタイピングが必要です。

ようなクラスより簡単に作成可能プロジェクトがあります:attrsattrsライブラリを使用して作成

from attrs import attrs, attrib 

@attrs(slots=True) 
class UnnormTan(object): 
    tan_id = attrib() 
    computer_name = attrib(default="INDETERMINATE") 
    # ... 

クラスが自動的に適切な平等のテスト、表現とハッシュ可能の世話をします。

このようなオブジェクトは、Pythonが提供できるデータの最もメモリ効率の良い表現です。それだけでは十分ではない場合もあります(十分ではない可能性もあります)。データをディスクにロードする必要があります。これを行う最も簡単な方法は、バンドルされたsqlite3 SQLite libraryのようなSQLデータベースを使用することです。 :memory:テンポラリデータベースを使用した場合でも、データベースは必要に応じてページをディスクにスワップアウトしてメモリ負荷を管理します。

0

あなたの主な問題は、メモリ内に完全にデータベースを作成しようとしているようです。 MySQLやPostgreSQLのような実際のデータベースを使うべきです。 peeweeやdjango ormのような素晴らしいORMをデータベースとのやりとりに使うことができます。

一方、データ全体を読み込めない場合は、処理できる部分にデータを分割できます。

モジュール「TinyDB」(http://tinydb.readthedocs.io/en/latest/)は、辞書の使用を続けたり、RAMを稼働させたりするのに役立ちます。

+0

SQLは別のサーバー上にあり、ネットワークの速度は残念なことに大きなボトルネックです。さらに、すべてのデータをデータベースに入れてそこのすべての行に取り組むと、私は実際にUPDATESを行うことができます...しかし、これらは検索が必要なために時間がかかります。私はとにかくすべての行に触れることを知っています... INSERTは、500のグループよりも約100倍高速でグループ化できます。 – gunslingor

+0

RAMの不足に遭遇しなければ、実際には他に選択肢がありませんが、データの格納と処理にはDATAベースを使用する必要があります。あなたは簡単にあなたのサーバー上のデータベースを設定することができ、ネットワークは関与しません。とにかくあなたの行を処理することができますが、重要なポイントは、今必要でないすべてのものをメモリに保存することです。 MongoDBを見てください。 –

+0

残念ながら、特定のコンプライアンス規制の法律がこれを妨げています...実際にはDBとAppサーバーのために別々のネットワークが必要です...残念ながら、企業は常に正しいことを設計するとは限らず、私はこれらのクレイジーな位置にいます。 – gunslingor

関連する問題