동기화 프리미티브¶
소스 코드: Lib/asyncio/locks.py
asyncio 동기화 프리미티브는 threading 모듈의 것과 유사하도록 설계되었습니다만 두 가지 중요한 주의 사항이 있습니다:
asyncio 프리미티브는 스레드 안전하지 않으므로, OS 스레드 동기화(이를 위해서는
threading을 사용하십시오)에 사용하면 안 됩니다.이러한 동기화 프리미티브의 메서드는 timeout 인자를 받아들이지 않습니다;
asyncio.wait_for()함수를 사용하여 시간제한이 있는 연산을 수행하십시오.
asyncio에는 다음과 같은 기본 동기화 프리미티브가 있습니다:
Lock¶
- class asyncio.Lock¶
asyncio 태스크를 위한 뮤텍스 록을 구현합니다. 스레드 안전하지 않습니다.
asyncio 록은 공유 자원에 대한 독점 액세스를 보장하는 데 사용될 수 있습니다.
Lock을 사용하는 가장 좋은 방법은
async with문입니다:lock = asyncio.Lock() # ... 나중에 async with lock: # 공유 상태를 액세스합니다
이는 다음과 동등합니다:
lock = asyncio.Lock() # ... 나중에 await lock.acquire() try: # 공유 상태를 액세스합니다 finally: lock.release()
버전 3.10에서 변경: loop 매개 변수를 제거했습니다.
- async acquire()¶
록을 얻습니다.
이 메서드는 록이 풀림(unlocked)이 될 때까지 기다리고, 잠김(locked)으로 설정한 다음
True를 반환합니다.잠금이 해제되기를 기다리는
acquire()에서 둘 이상의 코루틴 블록 될 때, 결국 한 개의 코루틴만 진행됩니다.록을 얻는 것은 공평(fair)합니다: 진행할 코루틴은 록을 기다리기 시작한 첫 번째 코루틴이 됩니다.
- release()¶
록을 반납합니다.
록이 잠김(locked)이면 풀림(unlocked)으로 재설정하고 돌아옵니다.
록이 풀림(unlocked)이면
RuntimeError가 발생합니다.
- locked()¶
록이 잠김(locked)이면
True를 반환합니다.
Event¶
- class asyncio.Event¶
이벤트 객체. 스레드 안전하지 않습니다.
asyncio 이벤트는 어떤 이벤트가 발생했음을 여러 asyncio 태스크에 알리는 데 사용할 수 있습니다.
Event 객체는
set()메서드로 참으로 설정하고clear()메서드로 거짓으로 재설정할 수 있는 내부 플래그를 관리합니다.wait()메서드는 플래그가 참으로 설정될 때까지 블록합니다. 플래그는 초기에 거짓으로 설정됩니다.버전 3.10에서 변경: loop 매개 변수를 제거했습니다.
예:
async def waiter(event): print('waiting for it ...') await event.wait() print('... got it!') async def main(): # Event 객체를 만듭니다. event = asyncio.Event() # 'event'가 설정될 때까지 대기 할 Task를 만듭니다. waiter_task = asyncio.create_task(waiter(event)) # 1초 동안 잠잔 후에 event를 설정합니다. await asyncio.sleep(1) event.set() # waiter 태스크가 끝날 때까지 기다립니다. await waiter_task asyncio.run(main())
- set()¶
이벤트를 설정합니다.
이벤트가 설정되기를 기다리는 모든 태스크는 즉시 깨어납니다.
- is_set()¶
이벤트가 설정되면
True를 반환합니다.
Condition¶
- class asyncio.Condition(lock=None)¶
Condition 객체. 스레드 안전하지 않습니다.
asyncio 조건 프리미티브는 태스크가 어떤 이벤트가 발생하기를 기다린 다음 공유 자원에 독점적으로 액세스하는데 사용할 수 있습니다.
본질에서, Condition 객체는
Event와Lock의 기능을 결합합니다. 여러 개의 Condition 객체가 하나의 Lock을 공유할 수 있으므로, 공유 자원의 특정 상태에 관심이 있는 다른 태스크 간에 공유 자원에 대한 독점적 액세스를 조정할 수 있습니다.선택적 lock 인자는
Lock객체나None이어야 합니다. 후자의 경우 새로운 Lock 객체가 자동으로 만들어집니다.버전 3.10에서 변경: loop 매개 변수를 제거했습니다.
Condition을 사용하는 가장 좋은 방법은
async with문입니다:cond = asyncio.Condition() # ... 나중에 async with cond: await cond.wait()
이는 다음과 동등합니다:
cond = asyncio.Condition() # ... 나중에 await cond.acquire() try: await cond.wait() finally: cond.release()
- async acquire()¶
하부 록을 얻습니다.
이 메서드는 하부 록이 풀림(unlocked)이 될 때까지 대기하고, 잠김(locked)으로 설정한 다음
True를 반환합니다.
- notify(n=1)¶
이 조건을 기다리는 n 태스크(기본적으로 1개)를 깨웁니다. 대기 중인 태스크가 n 개 보다 작으면 모두 깨어납니다.
이 메서드를 호출하기 전에 록을 얻어야 하고, 호출 직후에 반납해야 합니다. 풀린(unlocked) 록으로 호출하면
RuntimeError에러가 발생합니다.
- locked()¶
하부 록을 얻었으면
True를 돌려줍니다.
- notify_all()¶
이 조건에 대기 중인 모든 태스크를 깨웁니다.
이 메서드는
notify()처럼 작동하지만, 대기 중인 모든 태스크를 깨웁니다.이 메서드를 호출하기 전에 록을 얻어야 하고, 호출 직후에 반납해야 합니다. 풀린(unlocked) 록으로 호출하면
RuntimeError에러가 발생합니다.
- release()¶
하부 록을 반납합니다.
풀린 록으로 호출하면,
RuntimeError가 발생합니다.
- async wait()¶
알릴 때까지 기다립니다.
이 메서드가 호출될 때 호출하는 태스크가 록을 얻지 않았으면
RuntimeError가 발생합니다.이 메서드는 하부 잠금을 반납한 다음,
notify()나notify_all()호출 때문에 깨어날 때까지 블록합니다. 일단 깨어나면, Condition은 록을 다시 얻고, 이 메서드는True를 돌려줍니다.태스크가 이 호출에서 예기치 않게(spuriously) 반환될 수 있으므로, 호출자는 항상 상태를 다시 확인하고
wait()을 다시 수행할 준비를 해야 합니다. 이러한 이유로 대신wait_for()를 사용하는 것이 좋을 수도 있습니다.
Semaphore¶
- class asyncio.Semaphore(value=1)¶
Semaphore 객체. 스레드 안전하지 않습니다.
세마포어는 각
acquire()호출로 감소하고, 각release()호출로 증가하는 내부 카운터를 관리합니다. 카운터는 절대로 0 밑으로 내려갈 수 없습니다;acquire()가 0을 만나면,release()를 호출할 때까지 기다리면서 블록합니다.선택적 value 인자는 내부 카운터의 초깃값을 제공합니다 (기본적으로
1). 지정된 값이0보다 작으면ValueError가 발생합니다.버전 3.10에서 변경: loop 매개 변수를 제거했습니다.
Semaphore를 사용하는 가장 좋은 방법은
async with문입니다:sem = asyncio.Semaphore(10) # ... 나중에 async with sem: # 공유 자원으로 작업합니다
이는 다음과 동등합니다:
sem = asyncio.Semaphore(10) # ... 나중에 await sem.acquire() try: # 공유 자원으로 작업합니다 finally: sem.release()
- async acquire()¶
세마포어를 얻습니다.
내부 카운터가 0보다 크면, 1 감소시키고
True를 즉시 반환합니다. 0이면,release()가 호출될 때까지 기다린 다음True를 반환합니다.
- locked()¶
세마포어를 즉시 얻을 수 없으면
True를 반환합니다.
- release()¶
세마포어를 반납하고 내부 카운터를 1 증가시킵니다. 세마포어를 얻기 위해 대기하는 태스크를 깨울 수 있습니다.
BoundedSemaphore와 달리,Semaphore는acquire()호출보다 더 많은release()호출을 허용합니다.
BoundedSemaphore¶
- class asyncio.BoundedSemaphore(value=1)¶
제한된 세마포어 객체. 스레드 안전하지 않습니다.
제한된 세마포어는 초기 value 위로 내부 카운터를 증가시키면
release()에서ValueError를 발생시키는Semaphore버전입니다.버전 3.10에서 변경: loop 매개 변수를 제거했습니다.
Barrier¶
- class asyncio.Barrier(parties)¶
장벽 객체. 스레드 안전하지 않습니다.
장벽(barrier)은 parties 수의 태스크가 대기할 때까지 차단하는 간단한 동기화 프리미티브입니다. 태스크는
wait()메서드에서 대기할 수 있으며, 지정된 수의 태스크가wait()을 기다릴 때까지 차단됩니다. 그 시점에 모든 대기 중인 태스크가 동시에 해제됩니다.async with을wait()대기에 대한 대안으로 사용할 수 있습니다.장벽은 횟수에 상관없이 얼마든지 재사용할 수 있습니다.
예:
async def example_barrier(): # 3자 간 장벽 b = asyncio.Barrier(3) # 기다리는 태스크를 2개 만듭니다 asyncio.create_task(b.wait()) asyncio.create_task(b.wait()) await asyncio.sleep(0) print(b) # 세 번째 .wait() 호출은 장벽을 통과합니다 await b.wait() print(b) print("barrier passed") await asyncio.sleep(0) print(b) asyncio.run(example_barrier())
이 예제의 결과는 다음과 같습니다:
<asyncio.locks.Barrier object at 0x... [filling, waiters:2/3]> <asyncio.locks.Barrier object at 0x... [draining, waiters:0/3]> barrier passed <asyncio.locks.Barrier object at 0x... [filling, waiters:0/3]>
Added in version 3.11.
- async wait()¶
장벽을 통과합니다. 장벽에 속한 모든 태스크가 이 함수를 호출하면 모두 동시에 차단이 해제됩니다.
장벽에서 대기 중이거나 차단된 태스크가 취소되면, 해당 태스크는 상태가 유지되는 채로 장벽을 빠져나옵니다. 장벽의 상태가 “filling”인 경우, 대기 중인 태스크 수가 1 감소합니다.
반환 값은 각 태스크마다 다른 0부터
parties-1사이의 정수입니다. 이는 특별한 하우스키핑을 수행할 태스크를 선택하는 데 사용될 수 있습니다. 예::... async with barrier as position: if position == 0: # 오직 한 태스크만 이것을 인쇄합니다 print('End of *draining phase*')
태스크가 대기하는 동안 장벽이 파손되거나 재설정되면 이 메서드는
BrokenBarrierError예외를 발생시킬 수 있습니다. 태스크가 취소되면CancelledError가 발생할 수 있습니다.
- async reset()¶
장벽을 기본의 빈 상태로 되돌립니다. 대기 중인 모든 작업은
BrokenBarrierError예외를 수신합니다.장벽이 파손된 경우, 그대로 두고 새 장벽을 만드는 것이 나을 수 있습니다.
- async abort()¶
장벽을 파손된 상태로 만듭니다. 이로 인해 활성 또는 향후의 모든
wait()호출이BrokenBarrierError와 함께 실패하게 됩니다. 예를 들어, 태스크 중 하나가 중단되어야 해서 무한 대기 상황을 피해야 하는 경우에 사용합니다.
- parties¶
장벽을 통과하는 데 필요한 태스크 수.
- n_waiting¶
채워지는 동안 현재 장벽에서 대기 중인 태스크 수.
- broken¶
장벽이 파손된 상태이면
True인 불리언입니다.
- exception asyncio.BrokenBarrierError¶
이 예외는
RuntimeError의 하위 클래스로,Barrier객체가 재설정되거나 파손될 때 발생합니다.
버전 3.9에서 변경: await lock 이나 yield from lock 및/또는 with 문(with await lock, with (yield from lock))을 사용하여 록을 얻는 것은 제거되었습니다. 대신 async with lock을 사용하십시오.