2016-11-20 2 views
0

나는 꽤 asyncio에 익숙하고 다음과 같은 시나리오를 작성하는 방법에 대한 몇 가지 조언이 필요합니다. 나는 전화 번호부를 받아들이는 Cython 연장이있다. 전자는 새 이벤트가 도착할 때마다 실행됩니다. 그러나 그러한 이벤트를 수집하는 메카니즘을 시작하는 것은 블로킹 (blocking) 조작, 즉 메인 스레드를 차단합니다. Cython 확장은 asyncio.Queue도 허용하고 put_nowait 메서드를 콜백에서 호출합니다. 이제 이벤트를 처리 할 대기열의 사용자를 설정하려고합니다. 이 시나리오 뒤에 가능한 의사 코드 수 : 나는 예제를 실행하면asyncio 문제 및 조언

aioq = asyncio.Queue(1000)  
cext = CythonExtension(aioq) 

def c(aioq): 
    while not aioq.empty(): 
     e = yield from aioq.get() 
loop.create_task(c(aioq)) 

# i'm not sure how to run the event loop 
# and keep on initializing the cython extension 
# because this call also blocks... 
#loop.run_forever() 

# so i tried this. 

loop.run_in_executor(None, cext.start) <- this is a blocking operation 
# start the event loop 
loop.run_forever() 

asyncio 큐가 이벤트로 가득하지만, c 작업은 실행되지 않습니다 - 나는 큐에서 모든 이벤트를 얻을 수 아니다 . 이 문제를 해결하는 방법에 대한 피드백이나 조언을 부탁드립니다.

답변

1

정규 Python 코드는 특정 바이트 코드 연산이 실행 된 후에 다른 스레드가 회전하도록합니다. 예를 들어, this set of slides을 참조하십시오.이 메커니즘은 메커니즘 개선에 대해 설명하지만 메커니즘에 대해서도 설명합니다.

Cython은 바이트 코드를 실행하지 않으므로이 스와핑 메커니즘을 트리거하지 않으므로 Cython 스레드는 (찾은 것처럼) 무기한 차단됩니다. 그것은 라운드 간단한 방법은 cext.start에 주 사이 썬 루프에 다음 줄을 추가하는 것입니다 (그래서 정기적으로 실행) :

with nogil: 
    pass 

이 자료는 즉시 수있는 글로벌 통역 잠금 (GIL)를 되찾기 위해 시도 실행할 다른 스레드 (다른 스레드가 실행되고 나서 Cython이 대기해야하는 경우).

더 나은 옵션은 GIL (주로 파이썬 데이터 유형이 아닌 C 데이터 유형을 사용하는 비트)을 필요로하지 않는 Cython 코드의 비트를 식별하여 with nogil: 블록에 래핑하는 것입니다. 이렇게하면 다른 스레드가 실행되는 동안 Cython 코드가 유용한 작업을 계속할 수 있습니다.

+0

내 질문에는 답변이 없습니다. 그러나 GIL의 한계를 극복하기 위해 코드를 리팩터링하는 것이 동기였습니다. 매우 높은 성능 향상을 실험하고 있습니다. – Nedo

+0

음, 네가 원했던 방식이 아니라면 어떤면에서 도움이 되었기 때문에 기쁩니다! 나는 더 이상 도움이 될만한 'asyncio'를 정말로 이해하지 못한다는 것을 두려워한다. (Cython에서 때때로 나타나는 문제이기 때문에이 대답은 추측이다.) 'CythonExtension'에 대한 간단한 예제 코드를 보여 주면 다른 사람이 질문에 대답하는 데 도움이 될 수 있습니다 – DavidW

+0

다른 생각 :'c' 실행, 빈 대기열 찾기 및 확장 프로그램이 대기열에 아무것도 추가 할 시간이 없기 전에 끝내시겠습니까? (아니면 오해입니까?) – DavidW