문제

Twisted 문서를 통해 나는 다음과 같은 기술을 결합하는 것이 괜찮다고 믿게 되었습니다. reactor.spawnProcess() 그리고 threads.deferToThread() 동일한 응용 프로그램에서 반응기는 덮개 아래에서 이를 우아하게 처리할 것입니다.실제로 시도해 보니 응용 프로그램이 교착 상태에 빠졌다는 것을 알았습니다.여러 스레드를 단독으로 사용하거나 하위 프로세스를 단독으로 사용하면 모든 것이 정상입니다.

원자로 소스를 조사해 보니 SelectReactor.spawnProcess() 메소드는 단순히 호출 os.fork() 실행 중인 여러 스레드를 고려하지 않고.이는 교착 상태를 설명합니다. 왜냐하면 호출부터 시작하기 때문입니다. os.fork() 여러 동시 스레드가 실행되고 동일한 파일 설명자로 무엇을 수행하는지 아는 두 개의 프로세스가 있습니다.

SO에 대한 내 질문은 이 문제를 해결하기 위한 최선의 전략은 무엇입니까?

내가 염두에 두고 있는 것은 하위 클래스로 분류하는 것입니다. SelectReactor, 그래서 싱글톤이고 다음을 호출합니다. os.fork() 한 번만, 인스턴스화되면 즉시.하위 프로세스는 백그라운드에서 실행되며 상위 프로세스의 서버 역할을 합니다(파이프를 통한 개체 직렬화를 사용하여 서로 통신함).상위는 계속해서 애플리케이션을 실행하고 원하는 대로 스레드를 사용할 수 있습니다.통화 대상 spawnProcess() 부모 프로세스는 자식 프로세스에 위임되며, 자식 프로세스는 단 하나의 스레드만 실행되도록 보장되므로 다음을 호출할 수 있습니다. os.fork() 안전하게.

전에 이런 일을 해본 사람이 있나요?더 빠른 방법이 있나요?

도움이 되었습니까?

해결책 3

얼마 후 이 문제로 돌아와서 이렇게 하면 다음과 같은 사실을 발견했습니다.

reactor.callFromThread(reactor.spawnProcess, *spawnargs)

대신에:

reactor.spawnProcess(*spawnargs)

그러면 작은 테스트 케이스에서 문제가 사라집니다.Twisted 문서 "Using Processes"에 제가 이것을 시도하게 된 설명이 있습니다:"Twisted의 대부분의 코드는 스레드로부터 안전하지 않습니다.예를 들어, 프로토콜에서 전송으로 데이터를 쓰는 것은 스레드로부터 안전하지 않습니다."

나는 Jean-Paul이 언급한 다른 사람들도 비슷한 실수를 저지르고 있을 가능성이 있다고 생각합니다.리액터 및 기타 API 호출이 올바른 스레드 내에서 이루어지도록 하는 책임은 애플리케이션에 있습니다.그리고 분명히 매우 좁은 예외를 제외하면 "올바른 스레드"는 거의 항상 주 원자로 스레드입니다.

다른 팁

이 문제를 해결하기 위한 최선의 전략은 무엇입니까?

티켓을 제출하세요 (아마 그 이후 등록) 재현 가능한 테스트 사례를 사용하여 문제를 설명합니다(정확도 극대화를 위해).그런 다음 이를 구현하는 가장 좋은 방법(또는 플랫폼마다 다른 솔루션이 필요할 수 있음)이 무엇인지에 대한 논의가 있을 수 있습니다.

하위 프로세스 수확을 둘러싼 성능 문제를 해결하기 위해 하위 프로세스 생성을 돕기 위해 하위 프로세스를 즉시 생성한다는 아이디어가 이전에 제기되었습니다.이제 이러한 접근 방식으로 두 가지 문제가 해결되면 좀 더 매력적으로 보이기 시작합니다.이 접근 방식의 한 가지 잠재적인 어려움은 다음과 같습니다. spawnProcess 자식의 PID를 제공하고 신호를 보낼 수 있는 개체를 동기적으로 반환합니다.도중에 중간 프로세스가 있는 경우 구현해야 할 작업이 조금 더 늘어납니다. 그 전에 PID를 기본 프로세스로 다시 전달해야 하기 때문입니다. spawnProcess 보고.유사한 도전이 다음을 지원하는 것입니다. childFDs 더 이상 자식 프로세스의 파일 설명자만 상속하는 것이 불가능하기 때문입니다.

대체 솔루션(다소 더 해킹적일 수 있지만 구현 문제가 더 적을 수도 있음)은 다음을 호출하는 것일 수 있습니다. sys.setcheckinterval 전화하기 전에 매우 큰 번호로 os.fork, 상위 프로세스에서만 원래 확인 간격을 복원합니다.이는 프로세스에서 스레드 전환을 방지하는 데 충분합니다. os.execvpe 발생하여 모든 추가 스레드가 파괴됩니다.이는 특정 리소스(예: 뮤텍스 및 조건)를 잘못된 상태로 남겨두기 때문에 완전히 정확하지는 않지만 다음과 같이 사용합니다. deferToThread 그다지 흔하지 않으므로 귀하의 경우에 영향을 미치지 않을 수도 있습니다.

Jean-Paul이 답변에서 제공하는 조언은 훌륭하지만 ~해야 한다 작동합니다(대부분의 경우 작동합니다).

첫째, Twisted는 호스트 이름 확인에도 스레드를 사용하며 클라이언트 연결도 만드는 Twisted 프로세스의 하위 프로세스를 확실히 사용했습니다.그래서 이것은 실제로 작동할 수 있습니다.

두번째, fork() 하위 프로세스에 여러 스레드를 생성하지 않습니다. 설명하는 표준에 따르면 fork(),

프로세스는 단일 스레드로 생성됩니다.다중 스레드 프로세스가 fork()를 호출하는 경우 새 프로세스에는 호출 스레드의 복제본이 포함됩니다.

이제 그렇다고 해서 그런 것이 있다는 말은 아닙니다. 아니요 잠재적인 멀티스레딩 문제 spawnProcess;표준은 또한 다음과 같이 말합니다.

...오류를 피하기 위해 하위 프로세스는 exec 함수 중 하나가 호출될 때까지 비동기 신호 안전 작업만 실행할 수 있습니다.

비동기 신호에 안전한 작업만 사용되도록 보장할 수 있는 방법은 없다고 생각합니다.

따라서 스레드가 복제되는 하위 프로세스가 아니기 때문에 정확한 문제에 대해 좀 더 구체적으로 설명해주세요.

Linux의 fork()는 확실히 하위 프로세스에 하나의 스레드만 남깁니다.

Twisted에서 스레드를 사용할 때 스레드가 호출하도록 허용된 유일한 Twisted API는 callFromThread라는 것을 알고 있다고 가정합니다.다른 모든 Twisted API는 기본 리액터 스레드에서만 호출되어야 합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top