2

asyncio docs 읽기 : 오브젝트 asyncio 대부분의asyncio는 GIL을 고려하여 스레드로부터 안전하지 않을 수 있습니까?

는 스레드로부터 안전하지 않습니다. 이벤트 루프 외부의 객체에 액세스하는 경우에만 걱정해야합니다.

누군가가 이것을 설명하거나 asyncio의 오용으로 인해 스레드간에 공유되는 객체에 비동기 쓰기가 발생할 수 있다는 예를 들려 줄 수 있습니까? GIL은 한 번에 하나의 스레드 만 인터프리터를 실행할 수 있으므로 파이썬 객체를 읽고 쓰는 것과 같은 인터프리터에서 발생하는 이벤트는 스레드간에 쉽게 동기화된다는 것을 의미한다고 생각했습니다.

위의 인용문에서 두 번째 문장은 실마리처럼 들리지만 무엇을해야할지 모르겠습니다.

GIL을 해제하고 어쨌든 파이썬 객체에 쓰기를 결정하면 스레드가 항상 혼란을 야기 할 수 있다고 생각하지만, asyncio에만 해당되는 것은 아니므로 여기서는 문서를 언급하는 것이 아니라고 생각합니다.

CPython에서의 구현이 스레드 안전성이 보장되는 순간에도 특정 asyncio 객체에 대한 옵션이 스레드 안전하지 않도록 예약 된 asyncio PEP의 문제일까요?

+2

일부 작업에서는 동기화 할 수있는 여러 명령어가 필요합니다. Python을 다른 스레드에서 해석 할 수 있습니다. GIL은 결코 파이썬 프로그램을 결코 동기화하지 않습니다. asyncio와는 아무런 관련이 없습니다. - 단지 파이썬 객체가 파이썬 레벨이 아닌 C 레벨에서 쓰레드에 안전하다는 것을 확인합니다. –

답변

1

사실, 아니요, 각 스레드는 정확하게 인터프리터의 새 스레드입니다.

OS에서 관리하는 실제 스레드이며 Python 가상 머신 내에서 Python 코드 용으로 내부 관리 스레드가 아닙니다.

GIL은 OS 기반 스레딩이 Python 객체를 엉망으로 만드는 것을 방지하기 위해 필요합니다.

하나의 CPU에는 스레드가 있고 다른 CPU에는 스레드가 있다고 상상해보십시오. 어셈블리로 작성된 순수 병렬 스레드. 둘 다 동시에 레지스트리 값을 변경하려고합니다. 전혀 바람직한 상황이 아닙니다. 동일한 메모리 위치에 액세스하기위한 어셈블리 명령어는 언제 어디서 이동할 것인지에 대해 궁금해합니다. 결국 그러한 행동의 결과는 세분화 오류로 쉽게 이어질 수 있습니다. 글쎄, 우리가 C로 작성한다면, C는 그 부분을 제어한다. 그래서 이것은 C 코드에서 일어나지 않는다. GIL은 C 레벨에서 파이썬 코드에서도 똑같습니다. 따라서 Python 객체를 구현하는 코드는이를 변경할 때 원 자성을 잃지 않습니다. 다른 스레드가 일부 요소를 제거했기 때문에 다른 스레드에서 아래로 이동 한 목록에 값을 삽입하는 스레드를 상상해보십시오. GIL이 없으면 충돌이 발생합니다.

GIL은 스레드 내에서 코드의 원 자성에 대해 아무런 성과가 없습니다. 내부 메모리 관리를위한 것입니다.

deque()와 같은 스레드 안전 오브젝트가있는 경우에도 추가 잠금없이 둘 이상의 조작을 동시에 수행하는 경우 그 중간에 삽입 된 다른 스레드에서 결과를 얻을 수 있습니다. 그리고 웁스, 문제가 발생합니다!

하나의 스레드가 스택에서 객체를 가져 와서 그것에 대해 무언가를 검사하고, 조건이 올바르다면 말하십시오.

stack = [2,3,4,5,6,7,8] 
def thread1(): 
    while 1: 
     v = stack[0] 
     sleep(0.001) 
     if v%2==0: del stack[0] 
     sleep(0.001) 

물론 이것은 바보 같으며이를 피하려면 stack.pop (0)을 사용해야합니다. 그러나 이것은 하나의 예입니다.

그리고 각 스택에 스택 0을 추가하는 다른 스레드가 있습니다.002초 : 이제

def thread2(): 
    while 1: 
     stack.insert(0, stack[-1]+1) 
     sleep(0.002) 

당신이 할 경우 : thread2는() thread1 사이에 정확히에서 새 항목을 쌓아하려고 할 경우, 가능성이 있지만

thread(thread2,()) 
sleep(1) 
thread(thread1,()) 

(순간이있을 것이다)의 검색 및 삭제. 따라서 thread1()은 검사중인 항목 대신 새로 추가 된 항목을 제거합니다. 결과는 우리의 바램을 따르지 않습니다. 그래서 GIL은 스레드에서 수행중인 작업을 제어하지 않습니다. 스레드는 더 기본적인 의미에서 서로에게 무엇을하고 있는지를 제어합니다.

일부 이벤트 티켓 구매를 위해 서버를 작성했다고 가정 해보십시오. 두 명의 사용자가 연결되어 동일한 티켓을 동시에 구매하려고합니다. 조심하지 않으면 사용자는 다른 사람 위에 앉아서 끝낼 수 있습니다.

스레드 안전 개체는 작업을 수행하는 개체이며 첫 번째 작업이 완료 될 때까지 다른 작업을 수행 할 수 없도록합니다.

예를 들어 한 스레드에서 deque()를 반복하면서 다른 스레드가 무언가를 추가하려고하면 첫 번째 스레드가 반복 될 때까지 append()가 차단됩니다. 이것은 스레드로부터 안전합니다.

+0

'GIL은 우리가 쓰레드에서하는 일을 통제하지 않고, 단지 스레드가 서로에게하고있는 것을 제어하지 않습니다. -이 라인은 순금입니다. – xyres