2013-08-12 1 views
2

내가 가진 유틸리티 모듈에서 정리 루틴을 구현하려고합니다. 내 문제에 대한 해결책을 찾기 위해 마침내 weakref 콜백을 사용하여 정리 작업을 마쳤습니다. 그러나, 같은 모듈 내에서 개체에 대한 강력한 참조 때문에 예상대로 작동하지 않을까 우려됩니다. 설명하기 :인터프리터가 모듈 범위 변수 참조를 언제 릴리스합니까?

foo_lib.py

class Foo(object): 

    _refs = {} 

    def __init__(self, x): 

     self.x = x 
     self._weak_self = weakref.ref(self, Foo._clean) 
     Foo._refs[self._weak_self] = x 

    @classmethod 
    def _clean(cls, ref): 

     print 'cleaned %s' % cls._refs[ref] 

foo = Foo() 

다른 클래스는 다음 foo_lib.foo를 참조합니다. 나는 1.5.1에서 그런 종류의 참고 문헌 (http://www.python.org/doc/essays/cleanup/)을 찾았으나, foo은 콜백이 안정적으로 실행될 수있는 그런 방식으로 풀릴 것이라는 것을 완전히 깨닫지 못한다. 누구든지이 질문을 해결할 수있는 문서를 가르쳐 주시겠습니까? 종료 할 때

+0

당신이 실제로하고있는 일에 대해 weakref 정리 (또는, __del__')에 의존하고 싶지 않다고 생각합니다. 단단한 답을 내기가 어렵지만, 흥미로운 질문입니다. 인터프리터 파이널 라이 제이션이 실제로하는 일을 보게 해줘서 고마워. 왜냐하면 거기에는 흥미로운 것들이 있기 때문이다. – abarnert

답변

1

여기에서해야 할 일은 셧다운시 계산하기보다는 명시 적으로 강력한 참조를 명시 적으로 해제하는 것입니다.

특히 모듈이 출시되면 해당 전역이 출시 될 예정이지만 모듈이 출시 될 곳은 어디에도 기록되어 있지 않습니다. 따라서 종료 할 때 개체에 대한 참조가 여전히있을 수 있습니다. 그리고, 마티 피에 터스는 지적 :

__del__() 방법이 인터프리터 종료 여전히 존재하는 객체에 대해 호출되는 것을 보장 할 수 없습니다.당신이 당신의 객체 시간에는 (비 약한) 참조가 없는지 확인 할 수있는 경우

그러나 전에 인터프리터 종료, 당신은 정리 실행을 보장 할 수 있습니다.

핸들러를 사용하여 명시 적으로 자신을 지우는 데 사용할 수 있지만, 주 모듈의 끝에서 벗어나기 전에 (또는 sys.exit을 호출하거나 마지막 비 데몬 스레드를 종료하는 등) 명시 적으로 처리 할 수 ​​있습니다. 가장 간단한 방법은 전체 main 함수를 사용하여 with 또는 try/finally에 포장하는 것입니다.

또는 더 간단히 말해 코드 정리 코드를 __del__ 메서드 또는 weakref 콜백에 넣지 마십시오. with 또는 finally 또는 atexit에 정리 코드 자체를 넣기 만하면됩니다. 다른 답변에 단 댓글에서


:

는 내가 실제로 일반적으로 타이머에 의해 개방 유지 서브 프로세스를 종료되는 일을하려고하지만, 필요있어하는 것은 핵 공격을 할 때 프로그램 종료. 별도로 다른 프로세스를 모니터하고 죽이기 위해 데몬 프로세스를 시작하기 위해 이렇게하는 유일한 "신뢰성있는"방법입니까?

이런 종류의 작업을 수행하는 일반적인 방법은 외부에서 신호를 보낼 수있는 타이머로 교체하는 것입니다. 응용 프로그램 아키텍처와 사용중인 타이머의 종류 (예 : 원자로가 타이머를 작동시키는 단일 스레드 비동기 서버 또는 OS 타이머 메시지가 타이머 대 멀티를 울리는 단일 스레드 비동기 GUI 응용 프로그램)를 모르는 경우 스레드가 어디 스레드 대 sleep 간격 사이 스레드 ... 스레드 된 응용 프로그램, 더 구체적으로 설명하기 어렵다.

한편, 하위 프로세스를 처리하는 더 간단한 방법이 있는지 살펴볼 수도 있습니다. 예를 들어, 명시 적 프로세스 그룹을 사용하고 프로세스 대신 프로세스 그룹을 종료 할 수 있습니다 (세부 사항은 매우 다르지만 Windows 및 Unix 모두에서 모든 하위 작업이 종료됩니다). 또는 서브 프로세스에 파이프를 제공하고 파이프의 다른 쪽 끝이 내려갈 때 종료해야합니까?


설명서에는 삭제 된 왼쪽 참조가 삭제 된 순서에 대한 보장도 없습니다. 실제로 CPython을 사용하는 경우 Py_Finalize은 "임의 순서로 완료되었습니다"라고 구체적으로 말합니다.

The source은 흥미 롭습니다. 분명히 무작위로 추출한 것은 아니며 완전히 임의적 인 것도 아닙니다. 먼저 아무것도 남지 않을 때까지 GC를 수집 한 다음 GC 자체를 완료 한 다음 PyImport_Cleanup (기본적으로는 sys.modules.clear())을 수행 한 다음 다른 컬렉션을 주석 처리 한 후 (이유에 대한 설명과 함께) 마지막으로 _PyImport_Fini 이는 "내부 전용"으로 정의 됨).

하지만 이것은 모듈이 실제로 객체에 대한 유일한 (비 weak) 참조를 보유하고 있고 모듈 자체와 관련된 깨지 랄 수없는 사이클이 없다고 가정 할 때 모듈은 종료시 정리됩니다. 이 객체는 객체에 대한 마지막 참조를 삭제하여 객체를 정리합니다.(물론 내장 함수, 확장 모듈 및이 시점에서 여전히 존재하는 것에 대한 직접적인 참조가있는 것은 아닙니다. 그러나 fooFoo 전에 정리할 수 없기 때문에 위의 코드는 괜찮습니다.

이것은 CPython에만 해당되며 사실 CPython 3.3에만 해당됩니다. 버전에 맞는 관련 소스를 읽고 싶을 것입니다. 다시 말하면 문서에 명시 적으로 "무작위 순서대로"삭제된다는 것이 명시되어 있으므로 구현 관련 동작에 의존하고 싶지 않을 때 기대할 수 있습니다. 물론 귀하의 정리 코드의


여전히를 호출 할 보장 할 수 없습니다 . 예를 들어, 처리되지 않은 신호 (Unix에서) 또는 구조화 된 예외 (Windows에서)는 아무 것도 정리할 기회를주지 않고 인터프리터를 죽입니다. 그리고 그것을 위해 핸들러를 작성하더라도 누군가 항상 전원 코드를 가져올 수 있습니다. 따라서 완전히 견고한 디자인이 필요한 경우 저널링, 원자 적 파일 조작, 명시 적 승인과 함께 프로토콜 등을 사용하여 언제든지 정리없이 중단 할 수 있어야합니다.

+0

이것은 실제로 내 코드에서 테스트 프레임 워크에서 성능 최적화를 관리하고 있습니다. 여러 테스트에서 단일 가상 디스플레이 인스턴스를 시작 및 중지하고 디스플레이를 예약 및 해제하는 다른 코드를 추적하는 가상 디스플레이 관리자가 있습니다.타이머는 간단한 타이머 스레드로 디스플레이를 예약하는 사용자가없는 4 분 후에 가상 디스플레이를 종료합니다. 그러나 코가 테스트 스위트를 종료 할 때 아직 4 분이 경과하지 않은 경우 관리자는 모니터가 데몬 인 경우 디스플레이를 활성 상태로 두거나 스레드가 시간 초과 될 때까지 프로세스를 열린 상태로 유지합니다. –

+0

처음에는 atexit을보고 있었지만 더 영리하게 생각하는 것이 좋을 것이라고 생각했습니다. 아마 나는 덜 영리해질거야. :) –

+0

'임의'순서는 정리 순서가 사전에 묶여 있다는 사실에서 유래합니다. 3.3 랜덤 해싱이 소개되어 좀 더 무작위로 만들어졌습니다. 무작위로 '괴괴 망측 한'행동을 일으킨 예를 보려면 http://stackoverflow.com/questions/18163697/exception-typeerror-warning-sometimes-shown-sometimes-not-when-using-throw-meth를 참조하십시오. –

1

파이썬 모듈을 정리하고, 어떤 __del__ methods아마가 호출됩니다

__del__() 방법이 여전히 때 통역 종료 존재하는 객체에 대해 호출되는 것을 보장 할 수 없습니다. 밑줄로 시작

이름이 처음 삭제됩니다 :

버전 1.5을 시작으로, 파이썬을 보장하는 전역 이름이 시작하는 하나의 밑줄 다른 전역을 삭제하기 전에 모듈에서 삭제됩니다; 이러한 전역 변수에 대한 다른 참조가없는 경우 __del__() 메서드가 호출 될 때 가져온 모듈을 계속 사용할 수 있도록 보장 할 수 있습니다.

약한 참조 콜백은 __del__ 메서드와 동일한 메커니즘을 사용합니다. C 할당 해제 기능 (type->tp_dealloc).

foo 인스턴스는 Foo._clean 클래스 메서드에 대한 참조를 유지하지만, 글로벌 이름 Foo은 (는 CPython의에서 None를 할당) 이미 삭제 될 수 있습니다; 귀하의 방법 이 콜백이 등록되면 Foo을 결코 참조하지 않으므로 안전해야합니다.

+0

모든주의 사항 때문에 '__del__'을 특별히 피합니다. 나는 http://code.activestate.com/recipes/519621-object-finalization-without-__del__-and-without-ha/를 보았고, 나는 이것이 내가 weakref로 올바른 방향으로 가고 있다고 생각하게 만들었지 만, 그런 다음, 참조가 발표 될 때 명확한 정보를 추적 할 수 없다고 말했다. 'weakref' 콜백은'__del__'만큼 신뢰성이 있습니까? –

+0

동일한 메커니즘이 weakref 콜백을 호출하며 '__del__'을 호출합니다. –

+0

문서는 종료 할 때 모듈이 실제로 정리된다는 것을 어디서 보장합니까? 그것은 가지고있는 유용한 링크가 될 것입니다. – abarnert

관련 문제