-
Notifications
You must be signed in to change notification settings - Fork 10
/
0245.txt
138 lines (138 loc) · 11.2 KB
/
0245.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
예, 안녕하세요 포프입니다.
제가 얼마전에 Async void(에이싱크 보이드) 얘기를 좀 했었어요.
Async void를 언제 쓸까 말까 이런 비디오였는데
그 뒤에, 제가 거기서 Async void가 나쁘다.
그냥 event handler(이벤트 핸들러)에서만 쓰는게 좋다.
왜냐하면, event handler는 Task(테스크)를 반환을 못하는 경우가 있으니까
라는 얘기까지 했거든요.
근데, 제가.. 이 비디오를 만드는 시점으로, 어제
제가 원래 YouThumb(유썸)이라는 프로그램 있잖아요.
제 유튜브에 자동으로 이렇게, 글자 박아주고, 와갖고 제가 다운받아서 업로드 할 수 있는 그런 프로그램을 만들어서
오픈 소스로 만들어 놓은게 있는데
어제 그 비디오를 막 이렇게 하나하나.. 좀 밀려갖고 썸네일(Thumbnail)을 만들다 보니까
너무 시간이 들어갖고, 아.. 버튼클릭 하나로 모든걸 자동화 시키고 싶다.
라는 생각이 들어서
그 YouThumb이라는 프로그램을 다시 고치기 시작했어요.
이제 버튼 하나로 제대로 되게.
그러려면은 Youtube 로그인도 해야되고,
왜냐하면 이제 비디오 스케쥴(Schedule) 되 있는 거고, 그럼 Private(프라이빗) 비디오니까 그거를
뭐라그럴까.. 남들이 보지 못하는 상태에서 썸네일을 받을려면, 제 개인정보가 있어야 되거든요.
그래서, 그걸 작업하다 보니까
이제 Http client(클라이언트)로 유튜브 Rest Api를 쓰게 되고
그게 이제 Async 거든요? Http 클라이언트가 전부, 요즘은?
그래서 그걸 하다 보니까
Event Handler에서 그걸 또 해야 되는데, Event는 Void(보이드)만 받기 때문에, Async void를 쓸 일이 있더라구요.
그러다가, 마지막에 프로그램 나갈 때는.. 이제 뭐라그럴까
프로그램 닫을 때는 이제 Token(토큰) 받아놓은거, Access Token(억세스 토큰)이 있으니까, 로그인으로.
그거 Revoke(리보크)하는거까지 하면서 Async로 쏘니까.. Await가 안돼면서 별별일이 있어갖고
좀 이렇게 쓰다가.. 결국엔 다시 찾아봤어요. 예전에 읽었던 글을 다시 또 정독을 했는데.
결과적으론 이거에요.
Async void 대신 Async Task를 주로 쓰라는 이유.
Task 하고 형을 받을 수도 있고, 타입(Type)
그 형이 아니라 그냥 void를 하는거면 Task를 반환하는 이유는
Task를 만듦으로 인해서 그 호출하는 다른 프로그램에서 await를 걸어갖고 그 결과를 받아올 수가 있어요. 컨텍스트(context)를..
그 컨텍스트를 Capture(캡쳐)를 했을 때, 만약에 Async Task 안에서 익셉션(exception)이 났다면..
이 모든 익셉션. async로 도는 동안의 익셉션이 Aggregate(어그리게이트) 익셉션이라는 걸로 와 갖고 안에 다 들어가요.
그래서 try catch(트라이 캐치)가 되요.
물론
각 individual(인디비쥬얼)한 익셉션을 내부적으로 봐야되는건 좀 귀찮을 수도 있지만,
그래도 try-catch-await의 그 구문이 확실히 작동한다는 장점이 있고
그리고 await가 된다는거는 코드가 더이상 진행을 안하고, 거기서 뭐라그러죠
다시 거기서 실행이 되는거? async가 끝났을 때.
그런 개념이 있기 때문에 좋거든요.
근데 이제 async void를 쓸 때 문제는 뭐냐하면
Task를 반환을 하지 않기 때문에, await를 할 수 있는 방법이 없는거에요.
그럼 await를 할 수 있는 방법이 없으면 그냥 fire and forget으로 가요.
스레드(Thread)를 하나, (뭐 Task는 Thread pool이지만 어쨋든)
스레드를 하나 던지고, 그냥 얘가 결과가 어떻게 되든 모른 채 냅두겠다. 이게 async void 거든요?
그래서 이제
결국엔 이걸로 쓸 수 밖에 없는 경우가 있으니까 event handler 같은 경우 void를 받기 때문에, 대부분.
그걸 쓰는 경우고. 어찌보면은 event handler 같은 경우는.. 대부분이
단순한 UI(유아이)쪽 작업이거나 이런게 되게 많잖아요. WinForm(윈폼) 이런 쪽에서.
그래서 이게 굳이..
결과를 몰라도 되는 경우가 많아요. "이거 적용하면, 적용해라. 나는 결과가 뭐든지 신경을 안쓸게"
근데 문제는 exception을 못 걸고, catch를 못하기 때문에 이런 경우에는 보통..
앱 도메인(app domain) 수준에서, 그러니까 전체 애플리케이션 글로벌(global) 수준에서
Unhandled Exception을 잡는 법이 있잖아요?
그러니까 처리 되지 않은 익셉션을 잡아갖고 다 처리하겠다.
그래서 이런식으로 exception을 받아갖고 처리는 할 수 있는데
어찌보면은 글로벌 수준의 익셉션이죠
그래서 Async void가 반드시 나쁜건 아닌데
이제 가장 큰 문제는 그거더라구요. 일단은..
익셉션이 발생했을때 그게 어떤 일이 일어날지를 우리가 예측을 할수가 좀 어렵고
두번째는, async void를 해도 그 익셉션을 처리할 수 있는 방법이 있어요.
뭐, Syncronization Context를 직접 만들어서 하는 법도 있는데,
왠만한 어플리케이션에서는 이걸 하기는 너무 복잡하고
그럴바에는 차라리 Task를 걸고 await를 해라 이게 그거고
코드 유지 보수의 개념에서도 굉장히 달리진다는거죠.
예를 들면, Task를 반환하는 함수가 있으면
거기서 결과를 곧바로 빼서 못 쓰잖아요.
그럼 await를 해서 써야되잖아요. Reject(리젝트)를 걸면은 deadlock 걸 가능성이 있으니까
다 Result를 걸면은 데드락 가능성이 있거든요.
그러면 결국에는 await를 쓰기때문에 Syntax(신택스)적으로 compile(컴파일)할 때 이게 다 잡혀진다구요.
"아, 이거를.. Task를 반환하는 구나, await를 해야겠구나"
근데 async void로 해버리면
반환형 자체가, 반환되는게 없으니까 상관은 없는데
그 함수를 호출하는 순간 이미.. 그 Task가 반환되지 않는다는것만 봐서는, 그냥 코드를 짜는 입장에서는.
"아 이게 이 함수가 이미 끝났겠구나, 실행이 끝났겠구나"라고 가정을 하게 되거든요.
그거를.. 함수 이름에 마지막에 Async를 넣어줘갖고 좀 이렇게.. 좀 더 명확하게 써주는 법도 있지만.
여전히 실수할 가능성은 많다구요.
그러면, 이게 끝났다는 가정하에 다음 operation(오퍼레이션)을 돌리는데, 그 operation이 뻑이 나는거죠.
그러니까, 이런 저런걸 생각을 하면.
결국에는, async는 Task를 쓰는게 맞다는 이유가 코드 유지 보수성때문에, 왜냐하면 사람 머리 자체가.
A하고 B하고 C하고 D해야지 이렇게 생각하는건 쉬운데
A하고, B를 시작해두고, D, F를 하다가..
B가 끝났을 때 C를 해야지 이런거는.. 확실히 뭐라그럴까..
logic(로직)의 branch(브랜치)가 갈리기 때문에
사람이 생각하기에는 조금은 덜 쉬운 방법이에요.
언제나 사람들은 순서대로 가는거를 훨씬 쉬워하고
그래서 async를 가끔 어려워하시는 분들도 그런 개념인거같아요.
async던져두고 끝날때 기다린 다음에 이걸 한다라는 개념 자체가.
이것저것 써본 결과.
async.. 뭐라그럴까요.. void는 피할수 있는게 좋고
결국에 써야되는곳은 유일하게 event handler로 가는것만 좋다.
저도 그렇게 생각을 하구요.
그대신 event handler에서 보통 이렇게 들어오잖아요.
Event handler가 있으면.. 보통..
void event 이런식으로 들어오고
그 안에서 async를 호출해야 되는데 그렇게 하면 이걸 async로 바꿔야되는데 이건 복잡하니까..
얘를 어떻게 가는거냐하면, async void로 바꾸고
다른 함수를 호출을 하는 거에요, 다른 함수를.
그러니까 이 안에 event handler 자체에는 그냥
wrapper(래퍼)일 뿐이에요. 다른 함수 호출하는.. 그럼 다른 함수는 제대로 Task를 반환하고
그리고 거기서 Task를 반환하니까.. 다른 함수, event handler가 아닌 다른 함수가 이거를 호출한 다음에 await를 걸 수가 있는데
async void 그.. event handler. event handler 자체에서는 그냥 호출하고 잊어버리는거죠.
근데 이렇게 하면 장점이 유닛테스트를 하시는 분도 있을거고 그 함수를 다른데서 호출하시는 사람도 있을텐데.
그럴때는 이제 await를 걸어서 unit test(유닛테스트)를 걸어 갖고 async가 끝나는지 볼 수 있다는 장점도 있고.
근데, 저는 그것보다는 그냥..
가독성의 의미라고 봐요. async void가 들어가있다는 거 자체가..
그러니까 void 안에서 그거를 다른 async 함수를 호출하고 있다는거 자체가..
"아 이게 event handler 라서 이러는구나" 라는거에 가독성이 좋기 때문에
그 가독성의 입장에서 저는 괜찮은 방법이라고 생각해요.
그래서.. 딱 보고 가독성에서,
이게 이렇게 곧바로 wrapper가 되서 부르는거 보니까
어쩔 수 없이 event handler에서 이걸 피하기 위해 이렇게 한게 딱 한눈에 보이고
그러면 나중에 만약에 그거에 대한 결과를 기다려야되는 거나 그런 여러가지 일들이 있을때는
곧바로 아, 이게 이거 때문에 한게 딱 보이잖아요. 주석이 없어도.
이거를 다른식으로 해야겠구나.. bg wait로 기다리던, 아니면 무슨 timer로 시작해갖고 timer로 결과를 본다음에 알려주던.
그런 여러가지 방법으로 할 수가 있겠구나
아니면, 이제.. unhandled exception이 들어가면 그거 따라 이제 다른거 호출하고 이런식으로 간다거나..
async void에 대해서 제가 좀 이렇게..
뭉뚱그려 말하고, 왜 이게 나쁜건지 대답을 못 한 부분에 대해서 좀 고치려고 말한거고.
이거를 제대로 solve(솔브)하겠다 그러면 방법은 있는데..
제가 볼때는..
제가 예전에도 async가 좀 C#에서 문제가 많다라고 했던 부분이 기획 자체가 잘못된거같다. 디자인 자체가 잘못된거 같다.
그거는 아직도 저는 믿고 있구요. 오히려 이런 부분은 언어적인 부분에서 좀 더 해결이 가능하게 나와야 된다고 봐요.
void를 기대하는거에서 Task 해 갖고 await 할 수 있는걸 Syntax적으로 지원을 해준다거나
컴파일 수준에서 잡을 수 있는 그런것들이 저는 필요하다고 봐요.
그리고 fire-forget이면은 말그대로 fire-forget이라고 좀 더 명시적으로 말 할 수 있는.. 그러니까 async void 가 아니라..
async 하고.. Task가 있듯이..
fire and forget 이라던가(웃음) 뭐.. 이름이 좀 마음에 안들지만
그런식으로 키워드 지원으로 해서 좀 더 명확하게 가야된다고 보지
Configure await 문제도 그렇고, async void 문제도 그렇고
async는.. 누가 이거를 디자인해서 누가 넣는건지는 모르겠지만, C# 원래의
그 설계자는 아니라고 봐요.
그 사람이 설계한거랑 이거랑은 너무 퀄리티 차이가 많이 나는거 같아요.
그정도로 말하고
오랜만에 프로그래머 얘기했으니까 길게 안할게요. 프로그래밍 얘기했으니까(웃음)
포프였습니다.