-
Notifications
You must be signed in to change notification settings - Fork 10
/
0239.txt
170 lines (170 loc) · 10.5 KB
/
0239.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
예, 안녕하세요 포프입니다
오랜만에 async 얘기를 조금 해볼게요.
지금 얘기하는건 C#에 있는 async인데
C++의 async도 다르지 않을거라고 봐요
전에 몇 번 말씀을 드렸고
이제 async가 뭐냐? 그러면은 예전같은 경우에는 뭐라 그럴까
어떤 특정한 일을 비동기로 처리하려면
그 일마다 스레드를 하나를 만들고 했거든요?
제가 만약에 CPU에 코어가 4개가 달려있는데
스레드가 하드웨어 스레드가 4개죠
그럼 여기서 여러가지 일을 비동기로 하는거에요.
그러면 비동기의 일마다 스레드를 하나씩 뽑아가지고
그 예를 들어서 예전같은 잘못 만든 네트워크 시스템을 보면
커넥션이 하나 열릴 때마다
스레드를 하나 만들어서 돌렸거든요
커넥션이 100개면 스레드가 100개고
이 100개의 스레드를 하드웨어 4개 스레드가 처리해야 되니까
하나 당 25개씩 처리하는 건데 계속 바꿔야돼요
그러면 메모리 주소 바뀌고 바뀌고 이러면서
컨텍스트 스위치 때문에 속도 저하가 20%,30% 일어나거든요
그래서 이것을 했던게 스레드 기반이었고
그 다음에 나온 방법 중 하나가 태스크 기반이라고 해서
이렇게 어차피 스레드가 4개가 있을거고
잡을, 비동기화 잡을 100개를 해야되면 25개 잡을 만드는데
스레드로 만드는게 아니라
태스크라는 논리적인 단위로 만들어서
그 25개를 각 스레드마다 주는거죠
그래서 하나씩 하나씩 처리하는 것
이런식으로 아니면 뭐 이 스레드. 그러니까
뭐라 그럴까. 아니면 이걸 조금 조금씩 시간을 나눠서 처리하더라도
이 스레드를 바꾸지 않기 때문에 그에 대한 비용을 내지 않는 것
이런것을 태스크 시스템이라고 했어요
그래서 이제
C#에서는 async 코드라는 것 있잖아요?
async 해놓고 await 해놓고
이게 이런 태스크 기반을
태스크 시스템 기반으로 돌아가는 거에요
오늘 하려는 얘기는 그게 중요한게 아니지만
어쨌든 async, await가 스레드를 만드는 것 보다는
속도가 좀.. 성능이 빠르다. 낭비하는 시간이 없어서
그 정도로 이해해 주시면 좋고
최근에 그냥 async가 과연 또.. 웹.. 서버를 짜다가 최근에
웹 서버 프로그램을 짜다가 async를 다 바르는게 맞는건가?
과연 async가 빠른건가?
왜냐하면 async하는 것에 대한 오버헤드도 없지는 않거든요
그냥 async없이 쓰는것 보다
그래서 좀 자료를 찾아봤어요
그래서 결과적으로는 뭐냐면
이렇게 생각하시면 되더라구요. 예를 들어서
그.. 제 웹서버에 이 것을 처리해줄 수 있는
그.. 태스크 수가 예를 들어서
100개라고 해요. 100개
그러면
그 커넥션이 100개가 들어올테니까, 리퀘스트가 100개가 들어올 동안은
async를 쓰나 async를 안 쓰나 거의 속도가 비슷해요
비슷해요
그런데 그 다음부터가 재밌어져요
100개를 넘어가는 순간부터는 어떤 식이 일어나냐면
async를 쓴다면
이 100개를 가지고 자기네가 이렇게
교환을 하면서 계속 쓰는거거든요
그러니까 100개 넘고 200개가 들어왔으면
그냥 무작정 기다리는게 아니라
100개 실행하다가 잠깐 멈추고 다른게 100개 실행하다가
잠깐 멈추고 다른거 실행하다가.. 이런식으로 왔다갔다를 해요
그래서 결과적으로는
하나하나의 잡은 빨리 안 끝날수 있지만
모든 사람들에게 너무 느리게 끝나지는 않는
그러니까, 이제 웹에서 이미지 스트리밍을 받는 것만 봐도
이미지가 좌~악 보이기 시작하다가 '아~ 뭔가오는구나' 사람들이 기다리지만
이미지가 아직 오지도 않은 채, 시작도 안한 채 5초, 10초 기다리면 짜증을 내잖아요
그래서 그런것과 조금 가까워요
그런데 그것만이 문제가 아니고, 또 하나 재미있는게 뭐냐면
async를 안한 경우에는 결과적으로 뒤의 것은 앞의 것이 끝날때까지 기다려되는 거잖아요?
그러면 이 100개 끝나면. 모든게 동일한 시간에 끝난다면.
그러니까 하나하나 실행하는 시간이 똑같다면 스무스하게 끝나요.
기다리는 시간만 길어지고
그런데 재미있는게 뭐냐면
이렇게 하다가 이 중 하나. 중간에 있는 작동하는 하나가 있잖아요?
그게 다른것에 비해 100배의 시간이 걸린다.
그러면 이 뒤의 딜레이는 엄청나게 길어져요
그래서
자기가 가지고 있는 태스크 수. 스레드 풀에 있는 태스크 수보다 리퀘스트가 많지가 않다면
async를 하나, async를 하지 않으나
성능 상에는 별 차이가 없다고 보고
코드 가독성이라던가
오버헤드를 줄이는 측면에서 async를 안 쓰는게 훨씬 나은거에요
그런데, 이것을 나중에 스케일 시켜서 갑자기 로드가 몰릴 때
갑자기 하나가 팍! 스파이크를 뛰면서 엄청 시간 걸릴 때
뒤에 이제 막 1분, 2분씩 기다리는 일이 없게 하려면
그러니까 이거는 그래프가 이렇게(완만하게) 올라가다가
그러니까 이렇게 가다가 갑자기 이렇~게(급하게) 올라가 버려요
async를 안쓰면
근데 async를 쓰면 그래도 그래프가 되게 완만하게 올라가고 어느정도 유지가 되더라구요
그게 이제 피크가 없기 때문이라서 그런.. 뭐라 그럴까
scalability라 그러죠?
아니면 어느순간 로드가 왔을 때, 모든 사람이 잠깐씩은 느려질 수 있어도
한명이 막! 뭐 엄청나게 오래 기다리다가
타임아웃 되는 일이 없게 하는 그런것을 하기 위해서는
async가 나은 것 같더라구요
그래서 요즘 나오는 그런 베스트 프랙티스에 'async를 많이 써라'
라고 하는 얘기가 그것하고도 관련이 좀 있는것 같아요
그래서 저도 이제 고민을 하다가 '아 async로 다 바꾸긴 바꿔야 되겠구나'라는 생각은 하고는 있어요
그런데
좀.. 그렇죠..
웹이라는 곳은 아무래도 이제 어떤일이 일어날지 모르는 곳이니까
제가 이제 컨트롤 못하는 거니까
그래서 이제.. 뭐라 그럴까
웹 쪽에서는 async를 많이 쓰는게 맞는것 같고
게임 쪽에서는
굳이 async가 많이 필요한 경우가 많지는 않을 것 같아요
왜냐하면 게임쪽은 대부분 내가 컨트롤되는 environment고
안되는 거라곤 파일시스템, 네트워크 시스템 쪽이니까
이 쪽 빼놓고는 async가 그렇게 크게 의미가 있을 것 같지는 않고
그냥 새로운 것이기 때문에 써보겠다는 자세는 좀 버리는게 좋을 것 같아요
제가 한번에 나올 수 있는 리퀘스트가 async 잡이 몇개고
그 async잡에서 기다리는 대상. 네트워크가 됐든, 파일이 됐든
그것에 대한 제가 최소한의 '이 속도가 얼마다' 하는 확신이 있고 그것이 정해져 있다면
콘솔쪽은 특히나 그렇죠
그런데 굳이 async는 필요가 없는거 같더라구요
그래서 그런 얘기를 하고 싶었고
하나 할게 더 있어서요
async를 C#에서 쓰다보면 async void 를 쓰지 마라고 그래요
저도 한번 썼다가 난리가 났었는데
async 뒤에는 반드시
예외는 하나 있어요. 반드시 태스크가 들어와야 돼요
async void 를 쓰면, 이게 나중에
await가 안될거에요. 아마 태스크가
태스크가 아니고 void 면은 , 그래서 await가 안되면서 이게 나중에 컨텍스트를 다 지워버리고
나중에 쓰려고 할 때 에러 나거든요. 익셉션
그래서 async 뒤에 그 뭐라 그럴까
void
들어가면은 일단 무조건 잘못된 코드라고 보시고
예외는 이게 이벤트 핸들러일때만 돼요
이벤트 핸들러일때는
뭐 여러가지 이유가 있는데 저도 읽고 까먹었는데
어쨌든 태스크를 받지 않고 웬만하면 이벤트 핸들러에서
그리고 async void...
제가 정확히 읽지를 않아서 그것을 까먹었어요
읽은 뒤에 까먹었어요. 한참전에 읽어서.. 그런데
어쨌든 예외는 그렇게만 기억해 주시면될 것 같아요.
이벤트 핸들러가 아닌 이상은
죽어도 async 뒤에는 void 가 오면 안된다고. 무조건 태스크가 와야된다고
void 형이면 그냥 태스크가 와야되고 void 형이 아니면 태스크하고
각괄호(<>)열고 실제로 리턴되는 반환형 집어넣어야 되고
그 정도로만 기억해 주시면 될 것 같고
이게 제가.. 마지막으로 한마디만 더하죠
예전에 한번 C#의 기본동작이 잘못되고 있다는 얘기를 한적이 있잖아요?
이 async void 가 그래요
async void는 기본적으로 컴파일러 에러가 나야 정상이라고 봐요
그리고, 그러면 이제 이벤트 핸들러를 쓰는 사람들은 '아, 나는 이게 올바른것이라는 걸 알아'
'여기서는 async void 써도 된대' 그러면 거기다 어떤 다른 키워드를 써가지고
그 default behavior(기본 동작)를 오버라이드 해서, 이것은 되는것. 이런식으로 바꿔야 되거든요
그런데 이제 async의 깊은 것을 다. 사람이 어떻게 다 깊은 것을 공부하고 써요?
보이는데로 쓰는거지 사실은
그런데 컴파일 되고 내 컴퓨터에서 아무문제 없이 작동을 해
그러면 ok하고 넘어갔는데
이제 production environment(라이브 환경) 가면은 문제가 생기고 디버깅이 어려워 지는거죠
그런것을 막기위해 언어가 기본동작이 좋아야 된다는 것을 예전에 다른 비디오에서도 이야기 했죠
그런데 C#도 되게 좋았는데, 몇개 망가진게 있었고
async config await 도 망가진거라고 전에 얘기했고, 지금 생각하는 async void 도 망가진거에요.
기본적으로 async void 는 컴파일러 수준에서, 신택스 수준에서 안되게 막아버리고
그것을 오버라이드 하기 위해서는 다른 키워드를 써서 오버라이드를 했어야만
이게 제대로 된, 좀 더 실수가 적은 코드를 만들수 있는거죠
그래서 개인적으로는 좀 아쉬운부분
그 정도로 하고 오늘 비디오는 마칠게요.
굉장히 많은 이야기를 했구나
async void의 성능. async를 쓸까 안쓸까. 기본동작
그리고 async void
아.. 그정도. 포프였습니다.