동기화 프리미티브¶
소스 코드: 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()¶
이벤트를 설정합니다.
이벤트가 설정되기를 기다리는 모든 태스크는 즉시 깨어납니다.
- clear()¶
이벤트를 지웁니다 (재설정).
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를 돌려줍니다.작업이 이 호출에서 특이하게 반환될 수 있음에 유의하십시오. 이것이 호출자가 항상 상태를 재확인하고 :meth:`~Condition.wait`를 다시 수행할 준비가 되어 있어야 하는 이유입니다. 이러한 이유로, 대신 :meth:`~Condition.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)¶
장벽 객체. 스레드 안전하지 않습니다.
배리어는 parties 개의 작업이 기다릴 때까지 차단할 수 있게 해주는 간단한 동기화 프리미티브입니다. 작업들은
wait()메서드에서 기다릴 수 있으며, 지정된 수의 작업이wait()에서 기다리게 될 때까지 블록됩니다. 이 지점에서, 대기 중이던 모든 작업이 동시에 해제됩니다.:keyword:`async with`는 :meth:`~Barrier.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예외를 발생시킬 수 있습니다. 작업이 취소되면 :exc:`CancelledError`를 발생시킬 수도 있습니다.
- async reset()¶
배리어를 기본의 빈 상태로 되돌립니다. 그것을 기다리고 있는 모든 작업은
BrokenBarrierError예외를 수신합니다.배리어가 손상된 경우 그냥 두고 새것을 만드는 것이 더 좋을 수 있습니다.
- async abort()¶
배리어를 손상된 상태로 만듭니다. 이것은 :meth:`~Barrier.wait`에 대한 모든 활성 또는 미래 호출이 :class:`BrokenBarrierError`로 실패하게 만듭니다. 예를 들어, 무한 대기 작업을 방지하기 위해 작업 중 하나가 중단해야 하는 경우에 이것을 사용하십시오.
- parties¶
배리어를 통과하는 데 필요한 작업 수.
- n_waiting¶
작업이 채워지는 동안 배리어에서 현재 대기 중인 작업 수.
- broken¶
배리어가 손상된 상태이면
True인 불리언.
- exception asyncio.BrokenBarrierError¶
RuntimeError`의 서브 클래스인 이 예외는 :class:`Barrier객체가 재설정되거나 손상될 때 발생합니다.
버전 3.9에서 변경: await lock 이나 yield from lock 및/또는 with 문(with await lock, with (yield from lock))을 사용하여 록을 얻는 것은 제거되었습니다. 대신 async with lock을 사용하십시오.