파이썬 모듈이 다시로드 될 때마다 계산을 피하는 방법

StackOverflow https://stackoverflow.com/questions/195626

  •  10-07-2019
  •  | 
  •  

문제

거대한 사전 글로벌 변수를 사용하는 Python 모듈이 있습니다. 현재 계산 코드를 상단 섹션에 넣었습니다. 모듈의 처음 가져 오기 또는 재 장전은 1 분 이상이 걸릴 때마다 완전히 용납 할 수 없습니다. 다음 가져 오기/재 장전이 계산할 필요가 없도록 계산 결과를 어딘가에 저장하려면 어떻게해야합니까? CPICKLE을 시도했지만 파일 (1.3m)에서 사전 변수를로드하는 것은 계산과 대략 동일합니다.

내 문제에 대한 자세한 정보를 제공하려면

FD = FreqDist(word for word in brown.words()) # this line of code takes 1 min
도움이 되었습니까?

해결책

명확히하기 위해 : 모듈 본문의 코드는 ~ 아니다 모듈이 가져올 때마다 실행됩니다. 한 번만 실행되며, 그 후 향후 가져 오기는 재현하지 않고 이미 생성 된 모듈을 찾습니다. Cached 모듈 목록을 보려면 Sys.Modules를 살펴보십시오.

그러나 문제가 프로그램이 실행 된 후 첫 번째 가져 오기에 걸리는 시간 인 경우 파이썬 딕드 이외의 다른 방법을 사용해야 할 것입니다. 아마도 DBM 모듈 중 하나 인 SQLITE 데이터베이스와 같은 온 디스크 양식을 사용하는 것입니다.

인터페이스의 최소한의 변경을 위해 선반 모듈이 최선의 선택 일 수 있습니다. 이것은 DBM 모듈 사이에 상당히 투명한 인터페이스를 제공하여 임의의 파이썬 딕처럼 작용하여 선택 가능한 값을 저장할 수 있도록합니다. 예는 다음과 같습니다.

# Create dict with a million items:
import shelve
d = shelve.open('path/to/my_persistant_dict')
d.update(('key%d' % x, x) for x in xrange(1000000))
d.close()

그런 다음 다음 과정에서 사용하십시오. 도크 형식에 요청 된 키에 대해서만 조회가 수행되므로 모든 것이 메모리에로드 될 필요가 없으므로 큰 지연이 없어야합니다.

>>> d = shelve.open('path/to/my_persistant_dict')
>>> print d['key99999']
99999

실제 덕트보다 조금 느립니다. ~ 할 것이다 모든 키가 필요한 작업을 수행하는 경우 (예 : 인쇄를 시도해보십시오) 문제를 해결할 수 있습니다.

다른 팁

첫 번째 용도로 글로벌 VAR을 계산하십시오.

class Proxy:
    @property
    def global_name(self):
        # calculate your global var here, enable cache if needed
        ...

_proxy_object = Proxy()
GLOBAL_NAME = _proxy_object.global_name

또는 더 나은 방법은 특수 데이터 개체를 통해 필요한 데이터에 액세스하십시오.

class Data:
    GLOBAL_NAME = property(...)

data = Data()

예시:

from some_module import data

print(data.GLOBAL_NAME)

보다 장고 설정.

나는 당신이 Dict 문자를 소스에 붙여 넣었다고 생각합니다. 그게 1 분이 걸리는 것입니까? 나는 그것을 해결하는 방법을 모르겠지만 아마도이 독점을 인스턴스화하는 것을 피할 수 있습니다. 수입... 실제로 처음 사용될 때 게으르게 불쾌 할 수 있습니다.

당신은 그것을 사용해 볼 수 있습니다 육군 원수 c? 피클 하나 대신 모듈; 더 빠를 수 있습니다. 이 모듈은 Python에서 이진 형식으로 값을 저장하는 데 사용됩니다. 마샬이 당신의 요구에 맞는지 확인하려면 특히 다음 단락을 참고하십시오.

모든 파이썬 객체 유형이 지원되는 것은 아닙니다. 일반적으로, 값이 특정 파이썬 호출과 독립적 인 객체만이 모듈에서 작성하고 읽을 수 있습니다. 다음 유형은 지원됩니다. 없음, 정수, 긴 정수, 부동 소수 그 안에 포함 된 값이 자체적으로 지원되는 것처럼; 그리고 재귀 목록과 사전은 작성되어서는 안됩니다 (무한 루프를 유발할 것입니다).

안전한 편에 서서, DITT를 무시하지 않기 전에, DITT를 마시하지 않는 Python 버전은 거꾸로 호환성에 대한 보장이 없기 때문에 원수와 동일해야합니다.

'Shelve'솔루션이 너무 느리거나 충실한 것으로 판명되면 다른 가능성이 있습니다.

shelve 큰 데이터 세트로 인해 정말 느립니다. 나는 사용하고있다 레 디스 상당히 성공하고 썼다 Freqdist 래퍼 주변. 매우 빠르며 동시에 액세스 할 수 있습니다.

당신은 a를 사용할 수 있습니다 선반 전체 데이터를 메모리에로드하는 대신 데이터를 디스크에 저장합니다. 따라서 시작 시간은 매우 빠르지 만 트레이드 오프는 액세스 시간이 느려질 것입니다.

Shelve는 DICT 값도 피울 것이지만 모든 항목에 대한 스타트 업이 아니라 각 항목 자체에 대한 액세스 시간에만 (UN) 피클을 수행합니다.

수입 속도를 높이는 데 도움이되는 몇 가지 사항 :

  1. 파이썬을 실행할 때 -oo 플래그를 사용하여 Python을 실행해보십시오. 이렇게하면 모듈의 가져 오기 시간을 줄이는 일부 최적화가 수행됩니다.
  2. 더 빨리로드 할 수있는 별도의 모듈에서 사전을 작은 사전으로 나눌 수없는 이유가 있습니까?
  3. 최후의 수단으로서, 당신은 결과가 필요할 때까지 프로그램을 지연시키지 않도록 비동기 적으로 계산을 할 수 있습니다. 또는 멀티 코어 아키텍처를 활용하려면 사전을 별도의 프로세스에 넣고 IPC를 사용하여 데이터를 전달할 수도 있습니다.

그 말로, 나는 당신이 모듈을 처음 가져 오면 모듈 가져 오기에 지연되어서는 안된다는 것에 동의합니다. 다음은 몇 가지 다른 일반적인 생각입니다.

  1. 함수 내에서 모듈을 가져오고 있습니까? 그렇다면이 ~할 수 있다 실적 문제가 발생하여 모듈이 가져 오기 명령문에 부딪 칠 때마다 모듈이로드되는지 확인해야하므로 확인해야합니다.
  2. 당신의 프로그램은 멀티 스레드입니까? 멀티 스레드 앱에서 모듈 가져 오기에 코드를 실행하면 일부 Wonkiness 및 응용 프로그램 불안정성 (특히 CGITB 모듈)이 발생할 수있는 경우를 보았습니다.
  3. 이것이 글로벌 변수 인 경우 글로벌 변수 조회 시간이 로컬 변수 조회 시간보다 훨씬 길 수 있습니다. 이 경우 동일한 컨텍스트에서 여러 번 사용하는 경우 사전을 로컬 변수에 바인딩하여 상당한 성능 향상을 달성 할 수 있습니다.

그 말로, 조금 더 맥락없이 구체적인 조언을 제공하기가 어렵습니다. 보다 구체적으로, 어디에서 가져오고 있습니까? 그리고 계산은 무엇입니까?

  1. 계산 집중 부분을 별도의 모듈로 계산하십시오. 그런 다음 적어도 다시로드하면 기다릴 필요가 없습니다.

  2. 프로토콜 2를 사용하여 데이터 구조를 덤프하십시오. 시도하는 명령은 다음과 같습니다. cPickle.dump(FD, protocol=2). docstring에서 cPickle.Pickler:

    Protocol 0 is the
    only protocol that can be written to a file opened in text
    mode and read back successfully.  When using a protocol higher
    than 0, make sure the file is opened in binary mode, both when
    pickling and unpickling. 
    

나는이 같은 문제를 겪고 있습니다 ... 선반, 데이터베이스 등은 ...이 유형의 문제에 대해 너무 느립니다. 히트를 한 번 가져 와서 Redis와 같은 Inmemory Key/Val Store에 삽입해야합니다. 그것은 단지 기억에 남을 것입니다 (경고는 많은 양의 기억을 사용할 수 있으므로 전용 상자를 원할 수 있습니다). 다시로드 할 필요가 없으며 키를 위해 메모리를 찾을 수 있습니다.

r = Redis()
r.set(key, word)

word = r.get(key)

지연된 계산 아이디어를 확장하여 DICT를 필요에 따라 요소를 공급하는 클래스로 바꾸지 않겠습니까?

PSYCO를 사용하여 전반적인 실행 속도를 높일 수도 있습니다 ...

또는 값을 저장하기 위해 데이터베이스를 사용할 수 있습니까? Sqlobject를 확인하여 데이터베이스에 물건을 쉽게 저장할 수 있습니다.

이 문제에 대한 또 다른 분명한 해결책이 있습니다. 코드가 다시로드되면 원래 범위를 사용할 수 있습니다.

따라서 ... 이와 같은 작업을 수행하면이 코드가 한 번만 실행되도록합니다.

try:
    FD
except NameError:
    FD = FreqDist(word for word in brown.words())
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top