asyncio의 Task 객체는 cancel() 메서드를 통해 실행을 중단할 수 있습니다. 특정 작업이 중요한 경우, asyncio.shield() 함수를 사용하여 해당 작업이 외부에서 취소되는 것을 방지할 수 있습니다.
asyncio.shield()란?
asyncio.shield()는 Awaitable 객체를 감싸는 Future를 생성하며, 이 Future는 취소 요청을 흡수합니다. 즉, shield로 래핑된 작업은 다른 코드에 의해 취소되었더라도 내부적으로 계속 실행됩니다.
이 기능은 일부 작업만 선택적으로 취소하고 싶은 상황에서 유용합니다. 예를 들어 중요한 백그라운드 작업은 유지하면서 덜 중요한 작업만 종료해야 할 때 활용할 수 있습니다.
사용 방법
asyncio.shield()는 하나의 Awaitable 객체를 인자로 받아 Future 객체를 반환합니다:
# 작업 보호
protected_future = asyncio.shield(some_task)
# 대기
await protected_future
반환된 Future는 cancel() 호출 시 성공 여부를 반환하지만 실제 작업에는 영향을 미치지 않습니다:
# 보호된 Future 취소 시도
is_cancelled = protected_future.cancel()
Future를 대기하는 동안 CancelledError 예외가 발생할 수 있으므로 적절한 처리가 필요합니다:
try:
result = await asyncio.shield(background_work())
except asyncio.CancelledError:
print("보호된 작업 대기 중 취소됨")
중요한 점은 Future에 대한 취소 요청이 원본 작업으로 전파되지 않는다는 것입니다. 반면, 원본 작업 자체가 취소되면 shield도 함께 취소됩니다:
# 원본 작업 생성
original_task = asyncio.create_task(worker())
# 보호
guarded = asyncio.shield(original_task)
# shield만 취소 - 원본은 유지
guarded.cancel()
# 원본 작업 직접 취소 - shield도 함께 취소됨
original_task.cancel()
실제 예제
다음 예제에서는 중요한 작업을 shield로 보호하고, 다른 작업이 이를 취소하려는 시나리오를 구현합니다:
import asyncio
async def important_job(value):
await asyncio.sleep(1)
return value * 2
async def canceller(target):
await asyncio.sleep(0.2)
success = target.cancel()
print(f"취소 요청 결과: {success}")
async def main():
job_coro = important_job(5)
real_task = asyncio.create_task(job_coro)
safe_task = asyncio.shield(real_task)
# 다른 태스크가 safe_task를 취소하도록 함
asyncio.create_task(canceller(safe_task))
try:
outcome = await safe_task
print(f"결과 받음: {outcome}")
except asyncio.CancelledError:
print("Shield가 취소되었지만...")
await asyncio.sleep(1)
print(f"Shield 상태: {safe_task}")
print(f"실제 작업 상태: {real_task}")
asyncio.run(main())
실행 결과:
취소 요청 결과: True
Shield가 취소되었지만...
Shield 상태: <Future cancelled>
실제 작업 상태: <Task finished name='Task-2' coro=<important_job() done, defined at ...> result=10>
예제에서 확인할 수 있듯이 shield는 취소되었지만 내부 작업은 정상적으로 완료되었습니다. 이처럼 asyncio.shield()는 중요한 비동기 작업을 외부의 취소 요청으로부터 보호하는 데 효과적인 도구입니다.