C# async, await와 TAP 놀랍지만... 기술 이야기 2020. 4. 23. 00:16

Task Asynchronous Programming에 대해서 Microsoft에서 소개한 글을 읽고 간단하게 정리해 보았다. 국문도있지만, 기계 번역이라 이해하기 쉽지가 않다.

https://www.codeproject.com/Articles/562021/Asynchronous-models-and-patterns#usages

비동기 프로그래밍

규칙적인 시간 관계가 없는 것으로, 임의의 사상의 출현을 말하고 프로그램 실행에서는 명령순서 예측이 불가능한 것 - 비동기

비동기 프로그래밍은 비동기적으로 실행되는 부분을 포함한 프로그램을 구성하는 것이다. 비동기적 실행이라는 것은 실행의 종료시점과 실행주체가 동기화 되지않고 실행되는 것이다. 쉽게 설명하자면, 정확히 언제 끝날지 모르는 일이다.

비동기 프로그래밍의 대표적인 경험은 Web일 것이다. Javascript는 비동기 콜백이 엄청나게 많다. 너무 많아서 콜백 지옥이라고도 표현한다.ㅋ 익숙해지면 익숙한대로 요령것 프로그래밍이 가능하다.ㅎ

https://medium.com/gousto-engineering-techbrunch/avoiding-callback-hell-97734e303de1

타이젠 네이티브 어플리케이션 개발할 때도 콜백을 정말 많이 사용했는데, 확실히 다루기 까다롭다. 개발자를 힘들게하는 것 중 하나다. 그런데, .NET에서 너무 쉽게 비동기 프로그래밍을 할 수 있다는 사실에 놀랐다. 그래서 글을 쓰게 되었다.

async 와 await

The async and await keywords in C# are the heart of async programming. task-asynchronous-programming-model

간단하게 생각하면 정말 간단하다. Javascript ES8 async, await과 같은 느낌으로 사용하면 된다. 읽기 편하고, 쓰기 편하라고 만든만큼 참 쉽다. 읽기도, 쓰기도!

내가 여기서 설명을 붙이면 쓰레기를 양산하는 것 밖에 안되는 느낌일 정도로 좋은 설명과 예시가 이미 풍부하다. 절대 귀찮아서 그런거 아님!

thread

여기까지 접했을 때 thread에 대한 의문이 안 생기면 이상한거다. .NET runtime에서 처리해준다고 하지만, 어떻게? 비용은 어떻게되고? 개발자라면 당연히 궁금해야 할 내용이다.

The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread.

별도의 쓰레드를 따로 만들지도 않고, 멀티 쓰레딩이 필요하지도 않다고 한다. Task.Run으로 별도의 쓰레드를 만드는 것보다 훨씬 편리하고, 고질적인 race conditions 문제에 머리를 싸매도 되지 않는다! 이게 핵심이다! 그 동안 쓰레드 관리하느라 thread pool 만들고, race conditions 관리하느라 뮤텍스랑 세마포를 끼고 살았던, 그럼에도 불구하고 늘 이슈가 생겼던 아픔이 한방에 싸악~!

그럼에도 궁금한 것이, 그러면 무조건 같은 쓰레드에서 다시 실행시켜 준다는 것인가? 마치 자바스크립트의 Promise처럼 single-thread로 동작하면서 task queue를 사용하는 것인가? 궁금증을 해소하기 위해 stackoverflow를 찾았다.

async and await are single threaded Really?를 보면, 나와 같은 호기심과 의심을 갖은 사람이 많이 있다는 것을 알 수 있는데, 여기에 아주 적절한 포스트로 댓글 Async and Await 이 달려있다.

the awaitable will capture the current “context” and later apply it to the remainder of the async method.

내용을 간단하게 설명하자면, awaitawaitable을 전달인자로 받는 단항 연산자이다. awaitablecontext를 가지고 있다가 사용한다. UI thread라면, UI Context를 캡쳐하고 있다가 사용되므로 UI 구현에 큰 도움이 될 것이다. 하지만, UI Context가 아니라면?

  1. If you’re on a UI thread, then it’s a UI context.
  2. If you’re responding to an ASP.NET request, then it’s an ASP.NET request context.
  3. Otherwise, it’s usually a thread pool context.

UI Context가 아니라면? 그냥 thread pool에서 await 이후의 코드가 실행될 것이다! 조금 맥이 빠진다. 항상 같은 쓰레드로 다시 돌아가는 것은 아니니까 신경써서 사용해야 한다. Javascript와는 다르다! 그래도 적당한 곳에서 꽤 유용하게 사용할 수 있을 것 같다.

마치며

관련 가이드나 소개글이 엄청 기대감을 갖게 만들어서, 그 동안 멀티 쓰레딩 관리하느라 힘들었던 고통이 사라질 수 있다는 생각에 잠시나마 들뜬 마음으로 관련된 글들을 읽었다. 하지만, 모든 곳에 사용할 수는 없을 것 같고, 멀티 쓰레딩 프로그램은 여전히 많은 고민과 함께 조심스레 만들어야 한다.

물위에 오리가 유유히 거닐지만, 오리발은 쉴틈 없이 움직인다는 사실을 또 한번 새삼 떠올리게 된다. 개발 환경이나 언어는 점점 쉬워지지만, 그 아래 기술은 여전히 복잡하고 심지어 일부는 더 복잡해지고 있다. 내가 물 속 사정에 신경 끌 수 있는 입장이 아니라서...;;

이번에 놀란 것은 이미 아주 오래전에 소개되었다는 점과 .NET은 국문 커뮤니티와 블로그도 많다는 것이다. 역시 세상은 넓고, 고수는 많다.

There is No Thread

자바스크립트와 이벤트 루프

async/await에 대한 "There Is No Thread" 글의 부가 설명

Will HttpClient Async methods run in new threads