2017-12-11 6 views
-2

그래서 저는 1 년 동안 쓰고있는 30k 라인 프로그램을 가지고 있습니다. 기본적으로 비 정규화 된 데이터와 표준화되지 않은 데이터를 여러 소스에서 모으고 소스를 표준화 한 후 모든 것을 일치시킵니다.내 중독성을 파이썬 사전으로 자르는 방법

나는 모든 것을 주문 된 사전으로 작성했습니다. 이것은 열을 이름 붙이고 변경 가능하게 유지할 수있게하여 코드가 엉망진창에 걸쳐 값을 할당/수정할 수 있으므로 처리가 쉬워졌습니다.

그러나 현재 모든 사전에서 RAM이 부족합니다. 이후 namedtuples로 전환하면 문제가 해결된다는 것을 배웠습니다. 유일한 문제는 이러한 변경이 가능하지 않기 때문에 변환을 수행 할 때 한 가지 문제가 발생한다는 것입니다.

나는 불변성을 제거하기 위해 클래스를 사용할 수 있다고 믿지만, RAM 절감은 동일 할 것인가? 또 다른 옵션은 namedtuples을 사용하고 값을 변경할 필요가있을 때마다 새로운 namedtouples에 다시 할당하는 것입니다 (예 : NewTup = Tup (oldTup.odj1, oldTup.odj2, "something new"). 그러나 나는 명시적인 방법이 필요하다고 생각합니다. 그 이후의 오래된 파일이나 공간을 다시 파괴 할 수 있습니다.

결론적으로 필자의 입력 파일은 디스크 (많은 양의 데이터)에 대해 약 6GB입니다.이 데이터를 16GB RAM이 장착 된 서버에서 처리해야합니다. 및 4 GB 스왑. 원래 여러 가지 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 메모리 사용량을 줄이면 지금까지는 더 많은 데이터가 추가되거나 다른 프로세스에서 동일한 서버에 메모리를 사용하게되어 메모리 문제가 다시 발생합니다. 정말로 문제를 해결하려면 램에 많은 데이터를로드 할 필요가없는 솔루션이 필요합니다 (적절한 데이터베이스 - 관계형 또는 비 관계형 -이 솔루션의 일부일 수 있음). –

답변

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 
     # ... 

아마도 약간의 자세한 정보를 얻을 수 있습니다, 당신은 이들과 같은 사전 키를 사용해야하는 경우 더 많은 타이핑을해야합니다.

같은 클래스를 쉽게 만들 수 있습니다 프로젝트가있다 : attrs 다음 attrs 라이브러리를 생성

from attrs import attrs, attrib 

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

클래스가 자동으로 적절한 평등 테스트, 표현 및 hashability의주의를 기울입니다.

이러한 객체는 파이썬에서 제공 할 수있는 가장 효율적인 메모리 표현입니다. 이것이 충분하지 않은 경우 (그리고 충분하지 않을 수도 있습니다), 데이터를 디스크로 오프로드해야합니다. 가장 쉬운 방법은 번들 된 sqlite3 SQLite library처럼 SQL 데이터베이스를 사용하는 것입니다. :memory: 임시 데이터베이스를 사용하더라도 데이터베이스는 필요에 따라 페이지를 디스크로 스왑하여 메모리로드를 관리합니다.

0

당신의 주된 문제는 당신이 전적으로 메모리에 데이터베이스를 만들려고한다는 것입니다. MySQL이나 PostgreSQL과 같은 실제 데이터베이스를 사용해야합니다. peewee 나 django orm 같은 멋진 ORM을 데이터베이스와의 상호 작용에 사용할 수 있습니다.

전체 데이터를 처리 할 수없는 경우 데이터를 처리 할 수있는 부분으로 나눌 수 있습니다.

모듈 "TinyDB"(http://tinydb.readthedocs.io/en/latest/)는 사전을 계속 사용하고 RAM을 실행하지 않도록 도와줍니다.

+0

SQL이 별도의 서버에 있습니다. 네트워크 속도가 불행히도 커다란 병목입니다. 또한 데이터베이스의 모든 데이터를 가장 먼저 처리하고 모든 행에 대해 작업하면 업데이트 만 수행 할 수 있습니다. 그러나 검색이 필요하고 한 번에 하나씩 만 수행 할 수 있기 때문에 매우 느립니다. 나는 어쨌든 모든 행을 만질 것이라는 것을 안다. INSERTS는 500 번 그룹보다 약 100 배 빠른 시간에 500 명씩 그룹화 할 수있다. – gunslingor

+0

RAM 부족 현상에 직면하지 않으면 실제로 다른 선택의 여지가 없지만 DATA 저장소를 DATA 저장 및 처리에 사용하십시오. 서버에 데이터베이스를 쉽게 설치할 수 있으므로 관련 네트워크가 없습니다. 어쨌든 행을 처리 할 수 ​​있지만 요점은 메모리에없는 어딘가에 필요없는 모든 것을 저장하는 것입니다. MongoDB를 살펴보아야합니다. –

+0

불행히도 특정 컴플라이언스 규정의 법률로 인해 DB 및 App 서버에 별도의 네트워크가 필요합니다 ... 불행히도 회사는 항상 올바른 설계를하지는 못하고 이러한 미친 위치에 있습니다. – gunslingor

관련 문제