.NET: ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ ๋ฐ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์œ„ํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. 1 ๋ถ€

๋‚˜๋Š” Habr์— ์›๋ณธ ๊ธฐ์‚ฌ๋ฅผ ๊ฒŒ์‹œํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ๊ทธ ๋ฒˆ์—ญ๋ณธ์€ ๊ธฐ์—…์— ๊ฒŒ์‹œ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ธ”๋กœ๊ทธ.

์ง€๊ธˆ ์—ฌ๊ธฐ์„œ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋น„๋™๊ธฐ์‹์œผ๋กœ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ฑฐ๋‚˜ ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ์—ฌ๋Ÿฌ ๋‹จ์œ„์—์„œ ๋Œ€๊ทœ๋ชจ ์ž‘์—…์„ ๋ถ„ํ• ํ•ด์•ผ ํ•˜๋Š” ํ•„์š”์„ฑ์€ ์ปดํ“จํ„ฐ๊ฐ€ ์ถœํ˜„ํ•˜๊ธฐ ์ „์—๋„ ์กด์žฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋“ค์˜ ์ถœํ˜„์œผ๋กœ ์ด๋Ÿฌํ•œ ํ•„์š”์„ฑ์€ ๋งค์šฐ ๋ช…๋ฐฑํ•ด์กŒ์Šต๋‹ˆ๋‹ค. 2019๋…„์ธ ์ง€๊ธˆ, ์ €๋Š” 8๊ฐœ ์ด์ƒ์˜ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰๋˜๊ณ  ๋” ๋งŽ์€ ์Šค๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š” 8์ฝ”์–ด Intel Core ํ”„๋กœ์„ธ์„œ๊ฐ€ ํƒ‘์žฌ๋œ ๋…ธํŠธ๋ถ์—์„œ ์ด ๊ธ€์„ ์ž‘์„ฑํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทผ์ฒ˜์—๋Š” ๋ช‡ ๋…„ ์ „์— ๊ตฌ์ž…ํ•œ ์•ฝ๊ฐ„ ํ—ˆ๋ฆ„ํ•œ ์ „ํ™”๊ธฐ๊ฐ€ ์žˆ๋Š”๋ฐ, ๊ทธ ์ „ํ™”๊ธฐ์—๋Š” 16์ฝ”์–ด ํ”„๋กœ์„ธ์„œ๊ฐ€ ํƒ‘์žฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ฃผ์ œ๋ณ„ ๋ฆฌ์†Œ์Šค์—๋Š” ์ž‘์„ฑ์ž๊ฐ€ 20์ฝ”์–ด ํ”„๋กœ์„ธ์„œ๋ฅผ ํƒ‘์žฌํ•œ ์˜ฌํ•ด์˜ ์ฃผ๋ ฅ ์Šค๋งˆํŠธํฐ์„ ์นญ์ฐฌํ•˜๋Š” ๊ธฐ์‚ฌ์™€ ๋น„๋””์˜ค๊ฐ€ ๊ฐ€๋“ํ•ฉ๋‹ˆ๋‹ค. MS Azure๋Š” ์‹œ๊ฐ„๋‹น 128๋‹ฌ๋Ÿฌ ๋ฏธ๋งŒ์˜ ๋น„์šฉ์œผ๋กœ 2์ฝ”์–ด ํ”„๋กœ์„ธ์„œ์™€ XNUMXTB RAM์„ ๊ฐ–์ถ˜ ๊ฐ€์ƒ ๋จธ์‹ ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋ถˆํ–‰ํ•˜๊ฒŒ๋„ ์Šค๋ ˆ๋“œ์˜ ์ƒํ˜ธ ์ž‘์šฉ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์—†์œผ๋ฉด ์ตœ๋Œ€์น˜๋ฅผ ์ถ”์ถœํ•˜๊ณ  ์ด ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์ „๋ฌธ ์šฉ์–ด

ํ”„๋กœ์„ธ์Šค - ๊ฒฉ๋ฆฌ๋œ ์ฃผ์†Œ ๊ณต๊ฐ„์ธ OS ๊ฐœ์ฒด์—๋Š” ์Šค๋ ˆ๋“œ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
์‹ค - OS ๊ฐœ์ฒด, ์‹คํ–‰์˜ ๊ฐ€์žฅ ์ž‘์€ ๋‹จ์œ„, ํ”„๋กœ์„ธ์Šค์˜ ์ผ๋ถ€, ์Šค๋ ˆ๋“œ๋Š” ํ”„๋กœ์„ธ์Šค ๋‚ด์—์„œ ๋ฉ”๋ชจ๋ฆฌ ๋ฐ ๊ธฐํƒ€ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค.
๋ฉ€ํ‹ฐ ํƒœ์Šคํ‚น - OS ์†์„ฑ, ์—ฌ๋Ÿฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋™์‹œ์— ์‹คํ–‰ํ•˜๋Š” ๊ธฐ๋Šฅ
๋ฉ€ํ‹ฐ์ฝ”์–ด - ํ”„๋กœ์„ธ์„œ์˜ ์†์„ฑ, ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ์—ฌ๋Ÿฌ ์ฝ”์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ
๋‹ค์ค‘ ์ฒ˜๋ฆฌ - ์ปดํ“จํ„ฐ์˜ ์†์„ฑ, ๋ฌผ๋ฆฌ์ ์œผ๋กœ ์—ฌ๋Ÿฌ ํ”„๋กœ์„ธ์„œ์™€ ๋™์‹œ์— ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋Š” ๋Šฅ๋ ฅ
๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ โ€” ํ”„๋กœ์„ธ์Šค์˜ ์†์„ฑ, ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์— ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋ฅผ ๋ถ„์‚ฐ์‹œํ‚ค๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.
๋ณ‘ํ–‰ - ๋‹จ์œ„ ์‹œ๊ฐ„๋‹น ์—ฌ๋Ÿฌ ์ž‘์—…์„ ๋™์‹œ์— ๋ฌผ๋ฆฌ์ ์œผ๋กœ ์ˆ˜ํ–‰
๋น„๋™๊ธฐ โ€” ์ด ์ฒ˜๋ฆฌ๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ์ž‘์—…์„ ์‹คํ–‰ํ•˜๋ฉฐ, ์‹คํ–‰ ๊ฒฐ๊ณผ๋Š” ๋‚˜์ค‘์— ์ฒ˜๋ฆฌ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์€์œ 

๋ชจ๋“  ์ •์˜๊ฐ€ ์ข‹์€ ๊ฒƒ์€ ์•„๋‹ˆ๋ฉฐ ์ผ๋ถ€๋Š” ์ถ”๊ฐ€ ์„ค๋ช…์ด ํ•„์š”ํ•˜๋ฏ€๋กœ ๊ณต์‹์ ์œผ๋กœ ์†Œ๊ฐœ๋œ ์šฉ์–ด์— ์•„์นจ ์‹์‚ฌ ์š”๋ฆฌ์— ๋Œ€ํ•œ ๋น„์œ ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ๋น„์œ ์—์„œ ์•„์นจ ์‹์‚ฌ๋ฅผ ์š”๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ํ•˜๋‚˜์˜ ๊ณผ์ •์ž…๋‹ˆ๋‹ค.

์•„์นจ์— ์•„์นจ์‹์‚ฌ๋ฅผ ์ค€๋น„ํ•˜๋ฉด์„œ ๋‚˜๋Š” (CPU) ๋‚˜๋Š” ๋ถ€์—Œ์— ์˜จ๋‹ค (์ปดํ“จํ„ฐ). ๋‚˜๋Š” ์†์ด 2๊ฐœ ์žˆ๋‹ค(์ฝ”์–ด). ์ฃผ๋ฐฉ์—๋Š” ๋‹ค์–‘ํ•œ ๊ธฐ๊ธฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค(IO): ์˜ค๋ธ, ์ฃผ์ „์ž, ํ† ์Šคํ„ฐ, ๋ƒ‰์žฅ๊ณ . ๊ฐ€์Šค๋ฅผ ์ผœ๊ณ  ๊ทธ ์œ„์— ํ”„๋ผ์ดํŒฌ์„ ์˜ฌ๋ ค๋†“๊ณ  ์˜ˆ์—ด๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๊ธฐ๋ฆ„์„ ๋ถ€์–ด์ค๋‹ˆ๋‹ค(๋น„๋™๊ธฐ์‹, Non-Blocking-IO-Wait), ๋ƒ‰์žฅ๊ณ ์—์„œ ๊ณ„๋ž€์„ ๊บผ๋‚ด์„œ ์ ‘์‹œ์— ๋‹ด์€ ๋‹ค์Œ ํ•œ ์†์œผ๋กœ ์น˜์‹ญ์‹œ์˜ค (์Šค๋ ˆ๋“œ#1), ๋‘ ๋ฒˆ์งธ (์Šค๋ ˆ๋“œ#2) ์ ‘์‹œ(๊ณต์œ  ์ž์›)๋ฅผ ๋“ค๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ์ฃผ์ „์ž๋ฅผ ์ผœ๊ณ  ์‹ถ์€๋ฐ ์†์ด ๋ถ€์กฑํ•ด์š”.์Šค๋ ˆ๋“œ ๊ธฐ์•„) ์ด ์‹œ๊ฐ„ ๋™์•ˆ ํ”„๋ผ์ดํŒฌ์ด ๊ฐ€์—ด๋˜์–ด(๊ฒฐ๊ณผ ์ฒ˜๋ฆฌ ์ค‘) ํœ˜ํ•‘ํ•œ ๊ฒƒ์„ ๋ถ“์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ฃผ์ „์ž์— ์†์„ ๋ป—์–ด ์ „์›์„ ์ผœ๊ณ  ์–ด๋ฆฌ์„๊ฒŒ๋„ ๋ฌผ์ด ๋“๋Š” ๊ฒƒ์„ ์ง€์ผœ๋ด…๋‹ˆ๋‹ค.์ฐจ๋‹จ-IO-๋Œ€๊ธฐ), ๋น„๋ก ์ด ์‹œ๊ฐ„ ๋™์•ˆ ๊ทธ๋Š” ์˜ค๋ฏˆ๋ ›์„ ํœ˜์ “๋Š” ์ ‘์‹œ๋ฅผ ์”ป์„ ์ˆ˜ ์žˆ์—ˆ์ง€๋งŒ.

๋‘ ์†๋งŒ์œผ๋กœ ์˜ค๋ฏˆ๋ ›์„ ์š”๋ฆฌํ–ˆ๊ณ  ๊ทธ ์ด์ƒ์€ ์—†์ง€๋งŒ ๋™์‹œ์— ์˜ค๋ฏˆ๋ ›์„ ํœ˜์ “๋Š” ์ˆœ๊ฐ„ ์˜ค๋ฏˆ๋ › ํœ˜ํ•‘, ์ ‘์‹œ ์žก๊ธฐ, ํ”„๋ผ์ดํŒฌ ๊ฐ€์—ด์˜ ์„ธ ๊ฐ€์ง€ ์ž‘์—…์ด ํ•œ ๋ฒˆ์— ์ด๋ฃจ์–ด์กŒ์Šต๋‹ˆ๋‹ค. CPU๋Š” ์ปดํ“จํ„ฐ์—์„œ ๊ฐ€์žฅ ๋น ๋ฅธ ๋ถ€๋ถ„์ด๊ณ , IO๋Š” ๋ชจ๋“  ๊ฒƒ์ด ๋Š๋ ค์ง€๋Š” ๊ฒฝ์šฐ๊ฐ€ ๊ฐ€์žฅ ๋งŽ๊ธฐ ๋•Œ๋ฌธ์— IO์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” ๋™์•ˆ CPU๋ฅผ ๋ฌด์–ธ๊ฐ€๋กœ ์ ์œ ํ•˜๋Š” ๊ฒƒ์ด ํšจ๊ณผ์ ์ธ ์†”๋ฃจ์…˜์ธ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค.

๊ณ„์†ํ•ด์„œ ๋น„์œ ํ•˜์ž๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ์˜ค๋ฏˆ๋ ›์„ ๋งŒ๋“œ๋Š” ๊ณผ์ •์—์„œ ์˜ท๋„ ๊ฐˆ์•„์ž…์–ด๋ณธ๋‹ค๋ฉด, ์ด๋Š” ๋ฉ€ํ‹ฐํƒœ์Šคํ‚น์˜ ํ•œ ์˜ˆ๊ฐ€ ๋  ๊ฒƒ์ด๋‹ค. ์ค‘์š”ํ•œ ๋‰˜์•™์Šค: ์ปดํ“จํ„ฐ๋Š” ์‚ฌ๋žŒ๋ณด๋‹ค ์ด ๋ถ„์•ผ์—์„œ ํ›จ์”ฌ ๋›ฐ์–ด๋‚ฉ๋‹ˆ๋‹ค.
  • ์˜ˆ๋ฅผ ๋“ค์–ด ๋ ˆ์Šคํ† ๋ž‘์˜ ์—ฌ๋Ÿฌ ์š”๋ฆฌ์‚ฌ๊ฐ€ ์žˆ๋Š” ์ฃผ๋ฐฉ - ๋ฉ€ํ‹ฐ ์ฝ”์–ด ์ปดํ“จํ„ฐ.
  • ์‡ผํ•‘ ์„ผํ„ฐ์˜ ํ‘ธ๋“œ ์ฝ”ํŠธ์— ์žˆ๋Š” ๋งŽ์€ ๋ ˆ์Šคํ† ๋ž‘ - ๋ฐ์ดํ„ฐ ์„ผํ„ฐ

.NET ๋„๊ตฌ

.NET์€ ๋‹ค๋ฅธ ๋งŽ์€ ๊ฒƒ๋“ค๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์Šค๋ ˆ๋“œ ์ž‘์—…์— ๋Šฅ์ˆ™ํ•ฉ๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ๋ฒ„์ „์ด ๋‚˜์˜ฌ ๋•Œ๋งˆ๋‹ค ์ž‘์—…์„ ์œ„ํ•œ ์ ์  ๋” ๋งŽ์€ ์ƒˆ๋กœ์šด ๋„๊ตฌ, ์ฆ‰ OS ์Šค๋ ˆ๋“œ์— ๋Œ€ํ•œ ์ƒˆ๋กœ์šด ์ถ”์ƒํ™” ๊ณ„์ธต์ด ๋„์ž…๋ฉ๋‹ˆ๋‹ค. ์ถ”์ƒํ™” ๊ตฌ์„ฑ ์ž‘์—…์„ ํ•  ๋•Œ ํ”„๋ ˆ์ž„์›Œํฌ ๊ฐœ๋ฐœ์ž๋Š” ๋†’์€ ์ˆ˜์ค€์˜ ์ถ”์ƒํ™”๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ํ•˜๋‚˜ ์ด์ƒ์˜ ์ˆ˜์ค€ ์•„๋ž˜๋กœ ๋‚ด๋ ค๊ฐˆ ์ˆ˜ ์žˆ๋Š” ๊ธฐํšŒ๋ฅผ ์ œ๊ณตํ•˜๋Š” ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ์ด๋Š” ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ์‚ฐํƒ„์ด์œผ๋กœ ์ž์‹ ์˜ ๋ฐœ์„ ์˜๋Š” ๋ฌธ์ด ์—ด๋ฆฌ์ง€๋งŒ ๋•Œ๋กœ๋Š” ๋“œ๋ฌธ ๊ฒฝ์šฐ์ง€๋งŒ ํ˜„์žฌ ์ถ”์ƒํ™” ์ˆ˜์ค€์—์„œ ํ•ด๊ฒฐ๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. .

๋„๊ตฌ๋ž€ ํ”„๋ ˆ์ž„์›Œํฌ์™€ ํƒ€์‚ฌ ํŒจํ‚ค์ง€์—์„œ ์ œ๊ณตํ•˜๋Š” API(์‘์šฉ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ธํ„ฐํŽ˜์ด์Šค)๋Š” ๋ฌผ๋ก  ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ์ฝ”๋“œ์™€ ๊ด€๋ จ๋œ ๋ฌธ์ œ ๊ฒ€์ƒ‰์„ ๋‹จ์ˆœํ™”ํ•˜๋Š” ์ „์ฒด ์†Œํ”„ํŠธ์›จ์–ด ์†”๋ฃจ์…˜์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์Šค๋ ˆ๋“œ ์‹œ์ž‘ํ•˜๊ธฐ

Thread ํด๋ž˜์Šค๋Š” ์Šค๋ ˆ๋“œ ์ž‘์—…์„ ์œ„ํ•œ .NET์˜ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. ์ƒ์„ฑ์ž๋Š” ๋‘ ๋Œ€๋ฆฌ์ž ์ค‘ ํ•˜๋‚˜๋ฅผ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • ThreadStart โ€” ๋งค๊ฐœ๋ณ€์ˆ˜ ์—†์Œ
  • ParametrizedThreadStart - ๊ฐ์ฒด ์œ ํ˜•์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ํ•˜๋‚˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Start ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ํ›„ ์ƒˆ๋กœ ์ƒ์„ฑ๋œ ์Šค๋ ˆ๋“œ์—์„œ ๋Œ€๋ฆฌ์ž๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ParametrizedThreadStart ํ˜•์‹์˜ ๋Œ€๋ฆฌ์ž๊ฐ€ ์ƒ์„ฑ์ž์— ์ „๋‹ฌ๋œ ๊ฒฝ์šฐ ๊ฐœ์ฒด๊ฐ€ Start ๋ฉ”์„œ๋“œ์— ์ „๋‹ฌ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ๋กœ์ปฌ ์ •๋ณด๋ฅผ ์ŠคํŠธ๋ฆผ์œผ๋กœ ์ „์†กํ•˜๋Š” ๋ฐ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋น„์šฉ์ด ๋งŽ์ด ๋“œ๋Š” ์ž‘์—…์ด๋ฉฐ ์Šค๋ ˆ๋“œ ์ž์ฒด๋Š” ์ ์–ด๋„ ์Šคํƒ์— 1MB์˜ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•˜๊ณ  OS API์™€์˜ ์ƒํ˜ธ ์ž‘์šฉ์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฌด๊ฑฐ์šด ๊ฐœ์ฒด๋ผ๋Š” ์ ์€ ์ฃผ๋ชฉํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

new Thread(...).Start(...);

ThreadPool ํด๋ž˜์Šค๋Š” ํ’€์˜ ๊ฐœ๋…์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. .NET์—์„œ ์Šค๋ ˆ๋“œ ํ’€์€ ์—”์ง€๋‹ˆ์–ด๋ง์˜ ์ผ๋ถ€์ด๋ฉฐ Microsoft ๊ฐœ๋ฐœ์ž๋Š” ๋‹ค์–‘ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ์ตœ์ ์œผ๋กœ ์ž‘๋™ํ•˜๋„๋ก ๋งŽ์€ ๋…ธ๋ ฅ์„ ๊ธฐ์šธ์˜€์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜ ๊ฐœ๋…:

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹œ์ž‘๋˜๋Š” ์ˆœ๊ฐ„๋ถ€ํ„ฐ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์˜ˆ๋น„ ์Šค๋ ˆ๋“œ๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ์ƒ์„ฑํ•˜๊ณ  ์ด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์Šค๋ ˆ๋“œ๊ฐ€ ์ž์ฃผ ๊ทธ๋ฆฌ๊ณ  ๋Œ€๋Ÿ‰์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ ํ’€์€ ํ˜ธ์ถœ์ž์˜ ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•˜๋„๋ก ํ™•์žฅ๋ฉ๋‹ˆ๋‹ค. ์ ์‹œ์— ํ’€์— ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ ์—†์œผ๋ฉด ์Šค๋ ˆ๋“œ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ฐ˜ํ™˜๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๊ฑฐ๋‚˜ ์ƒˆ ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์Šค๋ ˆ๋“œ ํ’€์€ ์ผ๋ถ€ ๋‹จ๊ธฐ ์ž‘์—…์—๋Š” ์ ํ•ฉํ•˜์ง€๋งŒ ์ „์ฒด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ž‘์—…์—์„œ ์„œ๋น„์Šค๋กœ ์‹คํ–‰๋˜๋Š” ์ž‘์—…์—๋Š” ์ ํ•ฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ’€์˜ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ParametrizedThreadStart์™€ ๋™์ผํ•œ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ๊ฐ–๋Š” WaitCallback ์œ ํ˜•์˜ ๋Œ€๋ฆฌ์ž๋ฅผ ํ—ˆ์šฉํ•˜๋Š” QueueUserWorkItem ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ์œผ๋ฉฐ ์—ฌ๊ธฐ์— ์ „๋‹ฌ๋œ ๋งค๊ฐœ ๋ณ€์ˆ˜๋Š” ๋™์ผํ•œ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

ThreadPool.QueueUserWorkItem(...);

๋œ ์•Œ๋ ค์ง„ ์Šค๋ ˆ๋“œ ํ’€ ๋ฉ”์„œ๋“œ RegisterWaitForSingleObject๋Š” ๋น„์ฐจ๋‹จ IO ์ž‘์—…์„ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ์— ์ „๋‹ฌ๋œ ๋Œ€๋ฆฌ์ž๋Š” ๋ฉ”์„œ๋“œ์— ์ „๋‹ฌ๋œ WaitHandle์ด "Released"์ผ ๋•Œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

ThreadPool.RegisterWaitForSingleObject(...)

.NET์—๋Š” ์Šค๋ ˆ๋“œ ํƒ€์ด๋จธ๊ฐ€ ์žˆ์œผ๋ฉฐ ์ฒ˜๋ฆฌ๊ธฐ๊ฐ€ ํ’€์—์„œ ๊ฐ€์ ธ์˜จ ์Šค๋ ˆ๋“œ์—์„œ ํ˜ธ์ถœ๋œ๋‹ค๋Š” ์ ์—์„œ WinForms/WPF ํƒ€์ด๋จธ์™€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

System.Threading.Timer

์‹คํ–‰์„ ์œ„ํ•ด ํ’€์˜ ์Šค๋ ˆ๋“œ์— ๋Œ€๋ฆฌ์ž๋ฅผ ๋ณด๋‚ด๋Š” ๋‹ค์†Œ ์ƒ‰๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์ธ BeginInvoke ๋ฉ”์„œ๋“œ๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

DelegateInstance.BeginInvoke

์œ„์˜ ์—ฌ๋Ÿฌ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜์ธ Kernel32.dll Win32 API์˜ CreateThread์— ๋Œ€ํ•ด ๊ฐ„๋žตํ•˜๊ฒŒ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. extern ๋ฉ”์†Œ๋“œ์˜ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ๋•๋ถ„์— ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ์˜ ๋”์ฐํ•œ ์˜ˆ์—์„œ ๊ทธ๋Ÿฌํ•œ ํ˜ธ์ถœ์„ ๋‹จ ํ•œ ๋ฒˆ ๋ณธ ์ ์ด ์žˆ์œผ๋ฉฐ, ์ •ํ™•ํžˆ ์ด๊ฒƒ์„ ํ•œ ์ž‘์„ฑ์ž์˜ ๋™๊ธฐ๋Š” ์—ฌ์ „ํžˆ ๋‚˜์—๊ฒŒ ๋ฏธ์Šคํ„ฐ๋ฆฌ๋กœ ๋‚จ์•„ ์žˆ์Šต๋‹ˆ๋‹ค.

Kernel32.dll CreateThread

์Šค๋ ˆ๋“œ ๋ณด๊ธฐ ๋ฐ ๋””๋ฒ„๊น…

์‚ฌ์šฉ์ž๊ฐ€ ๋งŒ๋“  ์Šค๋ ˆ๋“œ, ๋ชจ๋“  ํƒ€์‚ฌ ๊ตฌ์„ฑ ์š”์†Œ ๋ฐ .NET ํ’€์€ Visual Studio์˜ ์Šค๋ ˆ๋“œ ์ฐฝ์—์„œ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ฐฝ์€ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์ด ๋””๋ฒ„๊ทธ ์ƒํƒœ์ด๊ณ  ์ค‘๋‹จ ๋ชจ๋“œ์— ์žˆ์„ ๋•Œ๋งŒ ์Šค๋ ˆ๋“œ ์ •๋ณด๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ ๊ฐ ์Šค๋ ˆ๋“œ์˜ ์Šคํƒ ์ด๋ฆ„๊ณผ ์šฐ์„  ์ˆœ์œ„๋ฅผ ํŽธ๋ฆฌํ•˜๊ฒŒ ํ™•์ธํ•˜๊ณ  ๋””๋ฒ„๊น…์„ ํŠน์ • ์Šค๋ ˆ๋“œ๋กœ ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Thread ํด๋ž˜์Šค์˜ Priority ์†์„ฑ์„ ์‚ฌ์šฉํ•˜๋ฉด OC์™€ CLR์ด ์Šค๋ ˆ๋“œ ๊ฐ„์— ํ”„๋กœ์„ธ์„œ ์‹œ๊ฐ„์„ ๋‚˜๋ˆŒ ๋•Œ ๊ถŒ์žฅ ์‚ฌํ•ญ์œผ๋กœ ์ธ์‹ํ•˜๋Š” ์Šค๋ ˆ๋“œ์˜ ์šฐ์„  ์ˆœ์œ„๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

.NET: ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ ๋ฐ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์œ„ํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. 1 ๋ถ€

ํƒœ์Šคํฌ ๋ณ‘๋ ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

TPL(์ž‘์—… ๋ณ‘๋ ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ)์€ .NET 4.0์— ๋„์ž…๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ์ด๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์„ ์œ„ํ•œ ํ‘œ์ค€์ด์ž ์ฃผ์š” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ์ด์ „ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ์ฝ”๋“œ๋Š” ๋ ˆ๊ฑฐ์‹œ๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๋‹ค. TPL์˜ ๊ธฐ๋ณธ ๋‹จ์œ„๋Š” System.Threading.Tasks ๋„ค์ž„์ŠคํŽ˜์ด์Šค์˜ Task ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. ์ž‘์—…์€ ์Šค๋ ˆ๋“œ์— ๋Œ€ํ•œ ์ถ”์ƒํ™”์ž…๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ๋ฒ„์ „์˜ C# ์–ธ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ž‘์—…(async/await ์—ฐ์‚ฐ์ž)์„ ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋Š” ์šฐ์•„ํ•œ ๋ฐฉ๋ฒ•์ด ์ƒ๊ฒผ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฐœ๋… ๋•๋ถ„์— ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ๊ฐ„๋‹จํ•˜๊ณ  ๋™๊ธฐ์ ์ธ ๊ฒƒ์ฒ˜๋Ÿผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๊ณ , ์Šค๋ ˆ๋“œ์˜ ๋‚ด๋ถ€ ์ž‘๋™์— ๋Œ€ํ•ด ๊ฑฐ์˜ ์ดํ•ดํ•˜์ง€ ๋ชปํ•œ ์‚ฌ๋žŒ์ด๋ผ๋„ ์ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜, ๊ธด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ๋•Œ ๋ฉˆ์ถ”์ง€ ์•Š๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. async/await ์‚ฌ์šฉ์€ ํ•˜๋‚˜ ๋˜๋Š” ์—ฌ๋Ÿฌ ๊ธฐ์‚ฌ์˜ ์ฃผ์ œ์ด์ง€๋งŒ ๋ช‡ ๋ฌธ์žฅ์œผ๋กœ ์š”์ ์„ ํŒŒ์•…ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  • async๋Š” Task ๋˜๋Š” void๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ์˜ ์ˆ˜์ •์ž์ž…๋‹ˆ๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  wait๋Š” ๋น„์ฐจ๋‹จ ์ž‘์—… ๋Œ€๊ธฐ ์—ฐ์‚ฐ์ž์ž…๋‹ˆ๋‹ค.

๋‹ค์‹œ ํ•œ ๋ฒˆ ๋ง์”€๋“œ๋ฆฌ์ง€๋งŒ, ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ(์˜ˆ์™ธ๊ฐ€ ์žˆ์Œ) wait ์—ฐ์‚ฐ์ž๋Š” ํ˜„์žฌ ์‹คํ–‰ ์Šค๋ ˆ๋“œ๋ฅผ ์ถ”๊ฐ€๋กœ ํ•ด์ œํ•˜๊ณ  ์ž‘์—…์ด ์‹คํ–‰์„ ๋งˆ์น˜๋ฉด ์Šค๋ ˆ๋“œ(์‹ค์ œ๋กœ ์ปจํ…์ŠคํŠธ๋ฅผ ๋งํ•˜๋Š” ๊ฒƒ์ด ๋” ์ •ํ™•ํ•ฉ๋‹ˆ๋‹ค)๋ฅผ ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค. , ๋‚˜์ค‘์— ์ž์„ธํžˆ ์„ค๋ช…) ๋ฉ”์„œ๋“œ๋ฅผ ๊ณ„์†ํ•ด์„œ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. .NET ๋‚ด์—์„œ ์ด ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ์ž‘์„ฑ๋œ ๋ฉ”์„œ๋“œ๊ฐ€ ์ „์ฒด ํด๋ž˜์Šค๋กœ ๋ฐ”๋€” ๋•Œ ํ•ญ๋ณต ๋ฐ˜ํ™˜๊ณผ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ƒํƒœ ๋จธ์‹ ์ด๋ฉฐ ์ด๋Ÿฌํ•œ ์ƒํƒœ์— ๋”ฐ๋ผ ๋ณ„๋„์˜ ์กฐ๊ฐ์œผ๋กœ ์‹คํ–‰๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ด€์‹ฌ ์žˆ๋Š” ์‚ฌ๋žŒ์€ ๋ˆ„๊ตฌ๋‚˜ asynั/await๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ , ์ปดํŒŒ์ผ๋Ÿฌ ์ƒ์„ฑ ์ฝ”๋“œ๊ฐ€ ํ™œ์„ฑํ™”๋œ JetBrains dotPeek์„ ์‚ฌ์šฉํ•˜์—ฌ ์–ด์…ˆ๋ธ”๋ฆฌ๋ฅผ ์ปดํŒŒ์ผํ•˜๊ณ  ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Task๋ฅผ ์‹œ์ž‘ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์˜ต์…˜์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ ์˜ˆ์ œ์—์„œ๋Š” ์œ ์šฉํ•˜์ง€ ์•Š์€ ์ƒˆ ์ž‘์—…์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค(์Šค๋ ˆ๋“œ.์ˆ˜๋ฉด(10000)), ๊ทธ๋Ÿฌ๋‚˜ ์‹ค์ œ ์ƒํ™œ์—์„œ๋Š” CPU๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๋ณต์žกํ•œ ์ž‘์—…์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

using TCO = System.Threading.Tasks.TaskCreationOptions;

public static async void VoidAsyncMethod() {
    var cancellationSource = new CancellationTokenSource();

    await Task.Factory.StartNew(
        // Code of action will be executed on other context
        () => Thread.Sleep(10000),
        cancellationSource.Token,
        TCO.LongRunning | TCO.AttachedToParent | TCO.PreferFairness,
        scheduler
    );

    //  Code after await will be executed on captured context
}

ํƒœ์Šคํฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ์˜ต์…˜์œผ๋กœ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

  • LongRunning์€ ์ž‘์—…์ด ๋นจ๋ฆฌ ์™„๋ฃŒ๋˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๋Š” ํžŒํŠธ์ž…๋‹ˆ๋‹ค. ์ฆ‰, ํ’€์—์„œ ์Šค๋ ˆ๋“œ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์—๊ฒŒ ํ•ด๋ฅผ ๋ผ์น˜์ง€ ์•Š๋„๋ก ์ด ์ž‘์—…์— ๋Œ€ํ•ด ๋ณ„๋„์˜ ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
  • AttachedToParent - ์ž‘์—…์„ ๊ณ„์ธต ๊ตฌ์กฐ๋กœ ์ •๋ ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ Task๋Š” ์ž์ฒด์ ์œผ๋กœ ์™„๋ฃŒ๋˜์–ด ํ•˜์œ„ ํ•ญ๋ชฉ์˜ ์‹คํ–‰์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์ƒํƒœ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • PreferFairness - ์‹คํ–‰์„ ์œ„ํ•ด ์ „์†ก๋œ ํƒœ์Šคํฌ๋ฅผ ๋‚˜์ค‘์— ์ „์†กํ•˜๊ธฐ ์ „์— ๋จผ์ € ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚ซ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Š” ๋‹จ์ง€ ๊ถŒ์žฅ์‚ฌํ•ญ์ผ ๋ฟ์ด๋ฉฐ ๊ฒฐ๊ณผ๋Š” ๋ณด์žฅ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ฉ”์„œ๋“œ์— ์ „๋‹ฌ๋œ ๋‘ ๋ฒˆ์งธ ๋งค๊ฐœ ๋ณ€์ˆ˜๋Š” CancellationToken์ž…๋‹ˆ๋‹ค. ์ž‘์—…์ด ์‹œ์ž‘๋œ ํ›„ ์ž‘์—… ์ทจ์†Œ๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋ ค๋ฉด ์‹คํ–‰ ์ค‘์ธ ์ฝ”๋“œ๋ฅผ CancellationToken ์ƒํƒœ์— ๋Œ€ํ•œ ๊ฒ€์‚ฌ๋กœ ์ฑ„์›Œ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ฒ€์‚ฌ๊ฐ€ ์—†์œผ๋ฉด CancellationTokenSource ๊ฐœ์ฒด์—์„œ ํ˜ธ์ถœ๋œ Cancel ๋ฉ”์„œ๋“œ๋Š” ์ž‘์—…์ด ์‹œ์ž‘๋˜๊ธฐ ์ „์—๋งŒ ์ž‘์—… ์‹คํ–‰์„ ์ค‘์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰ ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” TaskScheduler ์œ ํ˜•์˜ ์Šค์ผ€์ค„๋Ÿฌ ๊ฐœ์ฒด์ž…๋‹ˆ๋‹ค. ์ด ํด๋ž˜์Šค์™€ ๊ทธ ํ•˜์œ„ ํ•ญ๋ชฉ์€ ์Šค๋ ˆ๋“œ ์ „์ฒด์— ์ž‘์—…์„ ๋ฐฐํฌํ•˜๊ธฐ ์œ„ํ•œ ์ „๋žต์„ ์ œ์–ดํ•˜๋„๋ก ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์ž‘์—…์€ ํ’€์˜ ์ž„์˜ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

Wait ์—ฐ์‚ฐ์ž๋Š” ์ƒ์„ฑ๋œ ์ž‘์—…์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ฆ‰, ๊ทธ ๋’ค์— ์ž‘์„ฑ๋œ ์ฝ”๋“œ๊ฐ€ ๋Œ€๊ธฐ ์ „์˜ ์ฝ”๋“œ์™€ ๋™์ผํ•œ ์ปจํ…์ŠคํŠธ(์ข…์ข… ๋™์ผํ•œ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰๋จ)์—์„œ ์‹คํ–‰๋œ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค.

๋ฉ”์„œ๋“œ๋Š” async void๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์ฆ‰, wait ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ํ˜ธ์ถœ ์ฝ”๋“œ๋Š” ์‹คํ–‰์„ ๊ธฐ๋‹ค๋ฆด ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋ฉ”์„œ๋“œ๋Š” Task๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. async void๋กœ ํ‘œ์‹œ๋œ ๋ฉ”์„œ๋“œ๋Š” ๋งค์šฐ ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์ด๋Š” ํ™”์žฌ ๋ฐ ๋ง๊ฐ ์›์น™์— ๋”ฐ๋ผ ์ž‘๋™ํ•˜๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ๋˜๋Š” ๊ธฐํƒ€ ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค. ์‹คํ–‰์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆด ์ˆ˜ ์žˆ๋Š” ๊ธฐํšŒ๋ฅผ ์ œ๊ณตํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ Task๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

StartNew ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ์ž‘์—…๊ณผ ๋‹ค๋ฅธ ๋ชจ๋“  ์ž‘์—…์—์„œ false ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ConfigureAwait ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋Œ€๊ธฐ ํ›„ ์‹คํ–‰์€ ์บก์ฒ˜๋œ ์ปจํ…์ŠคํŠธ๊ฐ€ ์•„๋‹Œ ์ž„์˜์˜ ์ปจํ…์ŠคํŠธ์—์„œ ๊ณ„์†๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋Œ€๊ธฐ ํ›„ ์ฝ”๋“œ์— ๋Œ€ํ•ด ์‹คํ–‰ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ค‘์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ํ•ญ์ƒ ์ˆ˜ํ–‰๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํŒจํ‚ค์ง€๋˜์–ด ์ œ๊ณต๋  ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ MS์—์„œ ๊ถŒ์žฅํ•˜๋Š” ์‚ฌํ•ญ์ด๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

์ž‘์—… ์™„๋ฃŒ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ข€ ๋” ์ž์„ธํžˆ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ๊ธฐ๋Œ€๊ฐ€ ์กฐ๊ฑด์ ์œผ๋กœ ์ž˜ ์ˆ˜ํ–‰๋˜๋Š” ๊ฒฝ์šฐ์™€ ์กฐ๊ฑด์ ์œผ๋กœ ์ž˜๋ชป ์ˆ˜ํ–‰๋˜๋Š” ๊ฒฝ์šฐ์— ๋Œ€ํ•œ ์„ค๋ช…์ด ํฌํ•จ๋œ ์ฝ”๋“œ์˜ ์˜ˆ์ž…๋‹ˆ๋‹ค.

public static async void AnotherMethod() {

    int result = await AsyncMethod(); // good

    result = AsyncMethod().Result; // bad

    AsyncMethod().Wait(); // bad

    IEnumerable<Task> tasks = new Task[] {
        AsyncMethod(), OtherAsyncMethod()
    };

    await Task.WhenAll(tasks); // good
    await Task.WhenAny(tasks); // good

    Task.WaitAll(tasks.ToArray()); // bad
}

์ฒซ ๋ฒˆ์งธ ์˜ˆ์—์„œ๋Š” ํ˜ธ์ถœ ์Šค๋ ˆ๋“œ๋ฅผ ์ฐจ๋‹จํ•˜์ง€ ์•Š๊ณ  ์ž‘์—…์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ๊ฐ€ ์ด๋ฏธ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ๊ฒฐ๊ณผ ์ฒ˜๋ฆฌ๋กœ ๋Œ์•„๊ฐ‘๋‹ˆ๋‹ค. ๊ทธ๋•Œ๊นŒ์ง€ ํ˜ธ์ถœ ์Šค๋ ˆ๋“œ๋Š” ์ž์ฒด ์žฅ์น˜์— ๋‚จ์•„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‘ ๋ฒˆ์งธ ์˜ต์…˜์—์„œ๋Š” ๋ฉ”์„œ๋“œ ๊ฒฐ๊ณผ๊ฐ€ ๊ณ„์‚ฐ๋  ๋•Œ๊นŒ์ง€ ํ˜ธ์ถœ ์Šค๋ ˆ๋“œ๋ฅผ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํ”„๋กœ๊ทธ๋žจ์˜ ๊ท€์ค‘ํ•œ ๋ฆฌ์†Œ์Šค์ธ ์Šค๋ ˆ๋“œ๋ฅผ ๋‹จ์ˆœํ•œ ์œ ํœด ์ƒํƒœ๋กœ ์ ์œ ํ–ˆ์„ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์šฐ๋ฆฌ๊ฐ€ ํ˜ธ์ถœํ•˜๋Š” ๋ฉ”์„œ๋“œ์˜ ์ฝ”๋“œ์— ๋Œ€๊ธฐ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๊ณ  ๋™๊ธฐํ™” ์ปจํ…์ŠคํŠธ๊ฐ€ ์ดํ›„ ํ˜ธ์ถœ ์Šค๋ ˆ๋“œ๋กœ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ธฐ๋‹ค๋ฆฌ๋ฉด ๊ต์ฐฉ ์ƒํƒœ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ํ˜ธ์ถœ ์Šค๋ ˆ๋“œ๋Š” ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ์˜ ๊ฒฐ๊ณผ๊ฐ€ ๊ณ„์‚ฐ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๊ณ , ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ๋Š” ํ˜ธ์ถœ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰์„ ๊ณ„์†ํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜์ง€๋งŒ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

์ด ์ ‘๊ทผ ๋ฐฉ์‹์˜ ๋˜ ๋‹ค๋ฅธ ๋‹จ์ ์€ ๋ณต์žกํ•œ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ์ž…๋‹ˆ๋‹ค. ์‚ฌ์‹ค async/await๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋น„๋™๊ธฐ ์ฝ”๋“œ์˜ ์˜ค๋ฅ˜๋Š” ์ฒ˜๋ฆฌํ•˜๊ธฐ๊ฐ€ ๋งค์šฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. ์˜ค๋ฅ˜๋Š” ์ฝ”๋“œ๊ฐ€ ๋™๊ธฐ์ธ ๊ฒƒ์ฒ˜๋Ÿผ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. Task์— ๋™๊ธฐ์‹ ๋Œ€๊ธฐ ์—‘์†Œ์‹œ์ฆ˜์„ ์ ์šฉํ•˜๋ฉด ์›๋ž˜ ์˜ˆ์™ธ๋Š” AggregateException์œผ๋กœ ๋ณ€ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋ ค๋ฉด InnerException ์œ ํ˜•์„ ๊ฒ€์‚ฌํ•˜๊ณ  C# ์„ธ๊ณ„์—์„œ ๋” ์นœ์ˆ™ํ•œ catch ๋ธ”๋ก ์ฒด์ธ ๋Œ€์‹  ํ•˜๋‚˜์˜ catch ๋ธ”๋ก ๋‚ด์— if ์ฒด์ธ์„ ์ง์ ‘ ์ž‘์„ฑํ•˜๊ฑฐ๋‚˜ catch when ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์„ธ ๋ฒˆ์งธ์™€ ๋งˆ์ง€๋ง‰ ์˜ˆ์ œ๋„ ๊ฐ™์€ ์ด์œ ๋กœ ๋ถˆ๋Ÿ‰์œผ๋กœ ํ‘œ์‹œ๋˜์—ˆ์œผ๋ฉฐ ๋ชจ๋‘ ๋™์ผํ•œ ๋ฌธ์ œ๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

WhenAny ๋ฐ WhenAll ๋ฉ”์„œ๋“œ๋Š” ์ž‘์—… ๊ทธ๋ฃน์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋ฐ ๋งค์šฐ ํŽธ๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ž‘์—… ๊ทธ๋ฃน์„ ํ•˜๋‚˜๋กœ ๋ž˜ํ•‘ํ•˜์—ฌ ๊ทธ๋ฃน์˜ ์ž‘์—…์ด ์ฒ˜์Œ ํŠธ๋ฆฌ๊ฑฐ๋˜๊ฑฐ๋‚˜ ๋ชจ๋“  ์ž‘์—…์ด ์‹คํ–‰์„ ์™„๋ฃŒํ–ˆ์„ ๋•Œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

์Šค๋ ˆ๋“œ ์ค‘์ง€

๋‹ค์–‘ํ•œ ์ด์œ ๋กœ ํ๋ฆ„์ด ์‹œ์ž‘๋œ ํ›„ ํ๋ฆ„์„ ์ค‘์ง€ํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์—๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. Thread ํด๋ž˜์Šค์—๋Š” ์ ์ ˆํ•˜๊ฒŒ ์ด๋ฆ„์ด ์ง€์ •๋œ ๋‘ ๊ฐ€์ง€ ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ ์‚ฐ ะธ ์ธํ„ฐ๋ŸฝํŠธ. ์ฒซ ๋ฒˆ์งธ๋Š” ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ž„์˜์˜ ์ˆœ๊ฐ„์— ํ˜ธ์ถœํ•œ ํ›„ ๋ช…๋ น์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋™์•ˆ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ThreadAbortedException. ์ •์ˆ˜ ๋ณ€์ˆ˜๋ฅผ ์ฆ๊ฐ€์‹œํ‚ฌ ๋•Œ ์ด๋Ÿฌํ•œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒƒ์ด๋ผ๊ณ ๋Š” ์˜ˆ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ฃ ? ๊ทธ๋ฆฌ๊ณ  ์ด ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋Š” ๋งค์šฐ ์‹ค์ œ์ ์ธ ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค. CLR์ด ์ฝ”๋“œ์˜ ํŠน์ • ์„น์…˜์—์„œ ์ด๋Ÿฌํ•œ ์˜ˆ์™ธ๋ฅผ ์ƒ์„ฑํ•˜์ง€ ๋ชปํ•˜๋„๋ก ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์ด๋ฅผ ํ˜ธ์ถœ๋กœ ๋ž˜ํ•‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Thread.BeginCriticalRegion, Thread.EndCriticalRegion. finally ๋ธ”๋ก์— ์ž‘์„ฑ๋œ ๋ชจ๋“  ์ฝ”๋“œ๋Š” ์ด๋Ÿฌํ•œ ํ˜ธ์ถœ๋กœ ๋ž˜ํ•‘๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ด์œ ๋กœ ํ”„๋ ˆ์ž„์›Œํฌ ์ฝ”๋“œ์˜ ๊นŠ์ด์—์„œ ๋นˆ try๊ฐ€ ์žˆ๋Š” ๋ธ”๋ก์„ ์ฐพ์„ ์ˆ˜ ์žˆ์ง€๋งŒ finally๋Š” ๋น„์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Microsoft๋Š” ์ด ๋ฐฉ๋ฒ•์„ ๋„ˆ๋ฌด ๊ถŒ์žฅํ•˜์ง€ ์•Š์•„ .net ์ฝ”์–ด์— ํฌํ•จํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

์ธํ„ฐ๋ŸฝํŠธ ๋ฐฉ๋ฒ•์€ ๋” ์˜ˆ์ธก ๊ฐ€๋Šฅํ•˜๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์™ธ๋กœ ์ธํ•ด ์Šค๋ ˆ๋“œ๋ฅผ ์ค‘๋‹จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ThreadInterruptedException ์Šค๋ ˆ๋“œ๊ฐ€ ๋Œ€๊ธฐ ์ƒํƒœ์— ์žˆ๋Š” ์ˆœ๊ฐ„์—๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. WaitHandle, ์ž ๊ธˆ์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ ๋˜๋Š” Thread.Sleep์„ ํ˜ธ์ถœํ•œ ํ›„ ์ •์ง€๋˜๋Š” ๋™์•ˆ ์ด ์ƒํƒœ๋กœ ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค.

์œ„์— ์„ค๋ช…๋œ ๋‘ ์˜ต์…˜ ๋ชจ๋‘ ์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅ์„ฑ์œผ๋กœ ์ธํ•ด ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•ด๊ฒฐ์ฑ…์€ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ทจ์†Œ ํ† ํฐ ๊ทธ๋ฆฌ๊ณ  ์ˆ˜์—… ์ทจ์†Œ ํ† ํฐ ์†Œ์Šค. ์š”์ ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. CancellationTokenSource ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ์ด๋ฅผ ์†Œ์œ ํ•œ ์‚ฌ๋žŒ๋งŒ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ž‘์—…์„ ์ค‘์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ทจ์†Œ. CancellationToken๋งŒ ์ž‘์—… ์ž์ฒด์— ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค. CancellationToken ์†Œ์œ ์ž๋Š” ์ž‘์—…์„ ์ง์ ‘ ์ทจ์†Œํ•  ์ˆ˜ ์—†์œผ๋ฉฐ ์ž‘์—…์ด ์ทจ์†Œ๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€๋งŒ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ๋ถ€์šธ ์†์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ทจ์†Œ์š”์ฒญ๋จ ๋ฐ ๋ฐฉ๋ฒ• ThrowIfCancel์š”์ฒญ๋จ. ํ›„์ž๋Š” ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค TaskCancelledException Parroting ์ค‘์ธ CancellationToken ์ธ์Šคํ„ด์Šค์—์„œ Cancel ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ ๊ฒฝ์šฐ. ๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์ด ์ œ๊ฐ€ ์ถ”์ฒœํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์ด๋Š” ์˜ˆ์™ธ ์ž‘์—…์„ ์ค‘๋‹จํ•  ์ˆ˜ ์žˆ๋Š” ์ง€์ ์„ ์™„์ „ํžˆ ์ œ์–ดํ•จ์œผ๋กœ์จ ์ด์ „ ์˜ต์…˜์— ๋น„ํ•ด ๊ฐœ์„ ๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์Šค๋ ˆ๋“œ๋ฅผ ์ค‘์ง€ํ•˜๋Š” ๊ฐ€์žฅ ์ž”์ธํ•œ ์˜ต์…˜์€ Win32 API TerminateThread ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ ํ›„ CLR์˜ ๋™์ž‘์„ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. MSDN์—๋Š” ์ด ํ•จ์ˆ˜์— ๋Œ€ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‚ด์šฉ์ด ๊ธฐ๋ก๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. โ€œTerminateThread๋Š” ๊ฐ€์žฅ ๊ทน๋‹จ์ ์ธ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์œ„ํ—˜ํ•œ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. โ€œ

FromAsync ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ ˆ๊ฑฐ์‹œ API๋ฅผ ์ž‘์—… ๊ธฐ๋ฐ˜์œผ๋กœ ๋ณ€ํ™˜

ํƒœ์Šคํฌ๊ฐ€ ๋„์ž…๋œ ํ›„ ์‹œ์ž‘๋˜์–ด ๋Œ€๋ถ€๋ถ„์˜ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์กฐ์šฉํ•œ ๊ณตํฌ๊ฐ์„ ์•ˆ๊ฒจ์ค€ ํ”„๋กœ์ ํŠธ๋ฅผ ์šด ์ข‹๊ฒŒ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ํƒ€์‚ฌ API์™€ ํŒ€ API ๋ชจ๋‘๋ฅผ ํฌํ•จํ•œ ๋งŽ์€ ์˜ค๋ž˜๋œ API๋ฅผ ์ฒ˜๋ฆฌํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ณผ๊ฑฐ์— ๊ณ ๋ฌธ์„ ๊ฐ€ํ•œ ์ ์ด ์žˆ๋‹ค. ์šด ์ข‹๊ฒŒ๋„ .NET Framework ํŒ€์ด ์šฐ๋ฆฌ๋ฅผ ๋Œ๋ด์ฃผ์—ˆ์ง€๋งŒ ์•„๋งˆ๋„ ๋ชฉํ‘œ๋Š” ์šฐ๋ฆฌ ์ž์‹ ์„ ๋Œ๋ณด๋Š” ๊ฒƒ์ด์—ˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ .NET์—๋Š” ๊ธฐ์กด ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ์ž‘์„ฑ๋œ ์ฝ”๋“œ๋ฅผ ์ƒˆ๋กœ์šด ์ฝ”๋“œ๋กœ ์‰ฝ๊ฒŒ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค์–‘ํ•œ ๋„๊ตฌ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ์ค‘ ํ•˜๋‚˜๊ฐ€ TaskFactory์˜ FromAsync ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ ์˜ˆ์ œ์—์„œ๋Š” ์ด ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ WebRequest ํด๋ž˜์Šค์˜ ์ด์ „ ๋น„๋™๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ ์ž‘์—…์œผ๋กœ ๋ž˜ํ•‘ํ•ฉ๋‹ˆ๋‹ค.

object state = null;
WebRequest wr = WebRequest.CreateHttp("http://github.com");
await Task.Factory.FromAsync(
    wr.BeginGetResponse,
    we.EndGetResponse
);

์ด๊ฒƒ์€ ๋‹จ์ง€ ์˜ˆ์ผ ๋ฟ์ด๋ฉฐ ๊ธฐ๋ณธ ์ œ๊ณต ์œ ํ˜•์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ํ•„์š”๋Š” ์—†์ง€๋งŒ ๊ธฐ์กด ํ”„๋กœ์ ํŠธ์—๋Š” IAsyncResult๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” BeginDoSomething ๋ฉ”์„œ๋“œ์™€ ์ด๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” EndDoSomething ๋ฉ”์„œ๋“œ๊ฐ€ ๋„˜์ณ๋‚ฉ๋‹ˆ๋‹ค.

TaskCompletionSource ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ ˆ๊ฑฐ์‹œ API๋ฅผ ์ž‘์—… ๊ธฐ๋ฐ˜์œผ๋กœ ๋ณ€ํ™˜

๊ณ ๋ คํ•ด์•ผ ํ•  ๋˜ ๋‹ค๋ฅธ ์ค‘์š”ํ•œ ๋„๊ตฌ๋Š” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. ์ž‘์—…์™„๋ฃŒ์†Œ์Šค. ๊ธฐ๋Šฅ, ๋ชฉ์ , ์ž‘๋™ ์›๋ฆฌ ์ธก๋ฉด์—์„œ ๋ณด๋ฉด ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ThreadPool ํด๋ž˜์Šค์˜ RegisterWaitForSingleObject ๋ฉ”์„œ๋“œ์™€ ๋‹ค์†Œ ์œ ์‚ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ธฐ์กด ๋น„๋™๊ธฐ API๋ฅผ ์ž‘์—…์—์„œ ์‰ฝ๊ณ  ํŽธ๋ฆฌํ•˜๊ฒŒ ๋ž˜ํ•‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ชฉ์ ์„ ์œ„ํ•ด ๊ณ ์•ˆ๋œ TaskFactory ํด๋ž˜์Šค์˜ FromAsync ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•ด ์ด๋ฏธ ์ด์•ผ๊ธฐํ–ˆ๋‹ค๊ณ  ๋งํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๋Š” Microsoft๊ฐ€ ์ง€๋‚œ 15๋…„ ๋™์•ˆ ์ œ๊ณตํ•œ .net์˜ ๋น„๋™๊ธฐ ๋ชจ๋ธ ๊ฐœ๋ฐœ์˜ ์ „์ฒด ์—ญ์‚ฌ๋ฅผ ๊ธฐ์–ตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. TAP(์ž‘์—… ๊ธฐ๋ฐ˜ ๋น„๋™๊ธฐ ํŒจํ„ด) ์ด์ „์—๋Š” APP(๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํŒจํ„ด)๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋ฐฉ๋ฒ•์— ๊ด€ํ•œ ๊ฒƒ์ด์—ˆ์–ด ์‹œ์ž‘DoSomething์ด ๋Œ์•„์˜ค๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. IAsyncResult ๋ฐ ๋ฐฉ๋ฒ• ์ข…๋ฃŒ์ด๋ฅผ ๋ฐ›์•„๋“ค์ด๋Š” DoSomething๊ณผ ์ง€๋‚œ ๋ช‡ ๋…„ ๋™์•ˆ FromAsync ๋ฉ”์„œ๋“œ๋Š” ์™„๋ฒฝํ–ˆ์ง€๋งŒ ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด์„œ ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ๋น„๋™๊ธฐ ํŒจํ„ด(EAP), ๋น„๋™๊ธฐ ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

TaskCompletionSource๋Š” ์ด๋ฒคํŠธ ๋ชจ๋ธ์„ ์ค‘์‹ฌ์œผ๋กœ ๊ตฌ์ถ•๋œ ์ž‘์—… ๋ฐ ๋ ˆ๊ฑฐ์‹œ API๋ฅผ ๋ž˜ํ•‘ํ•˜๋Š” ๋ฐ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น ์ž‘์—…์˜ ๋ณธ์งˆ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด ํด๋ž˜์Šค์˜ ๊ฐœ์ฒด์—๋Š” Task ์œ ํ˜•์˜ ๊ณต์šฉ ์†์„ฑ์ด ์žˆ์œผ๋ฉฐ, ํ•ด๋‹น ์ƒํƒœ๋Š” TaskCompletionSource ํด๋ž˜์Šค์˜ SetResult, SetException ๋“ฑ ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ œ์–ด๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด Task์— Wait ์—ฐ์‚ฐ์ž๊ฐ€ ์ ์šฉ๋œ ์œ„์น˜์—์„œ๋Š” TaskCompletionSource์— ์ ์šฉ๋œ ๋ฉ”์„œ๋“œ์— ๋”ฐ๋ผ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ์‹คํ–‰๋˜๊ฑฐ๋‚˜ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค. ์—ฌ์ „ํžˆ ๋ช…ํ™•ํ•˜์ง€ ์•Š๋‹ค๋ฉด ์ผ๋ถ€ ์ด์ „ EAP API๊ฐ€ TaskCompletionSource๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์—…์— ๋ž˜ํ•‘๋œ ์ด ์ฝ”๋“œ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ž‘์—…์ด ์™„๋ฃŒ๋จ ์ƒํƒœ๋กœ ์ „ํ™˜๋˜๊ณ  ๋Œ€๊ธฐ ์—ฐ์‚ฐ์ž๋ฅผ ์ ์šฉํ•œ ๋ฉ”์„œ๋“œ๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์ด ํƒœ์Šคํฌ๋Š” ๊ฐ์ฒด๋ฅผ ์ˆ˜์‹ ํ•œ ํ›„ ์‹คํ–‰์„ ์žฌ๊ฐœํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ.

public static Task<Result> DoAsync(this SomeApiInstance someApiObj) {

    var completionSource = new TaskCompletionSource<Result>();
    someApiObj.Done += 
        result => completionSource.SetResult(result);
    someApiObj.Do();

    result completionSource.Task;
}

์ž‘์—…์™„๋ฃŒ์†Œ์Šค ํŒ & ์š”๋ น

TaskCompletionSource๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด์ „ API๋ฅผ ๋ž˜ํ•‘ํ•˜๋Š” ๊ฒƒ์ด ์ „๋ถ€๋Š” ์•„๋‹™๋‹ˆ๋‹ค. ์ด ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์Šค๋ ˆ๋“œ๋ฅผ ์ฐจ์ง€ํ•˜์ง€ ์•Š๋Š” ์ž‘์—…์— ๋Œ€ํ•œ ๋‹ค์–‘ํ•œ API๋ฅผ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ๋Š” ํฅ๋ฏธ๋กœ์šด ๊ฐ€๋Šฅ์„ฑ์ด ์—ด๋ฆฝ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์šฐ๋ฆฌ๊ฐ€ ๊ธฐ์–ตํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ŠคํŠธ๋ฆผ์€ ๊ฐ’ ๋น„์‹ผ ๋ฆฌ์†Œ์Šค์ด๋ฉฐ ๊ทธ ์ˆ˜๋Š” ์ฃผ๋กœ RAM ์–‘์— ๋”ฐ๋ผ ์ œํ•œ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ œํ•œ์€ ์˜ˆ๋ฅผ ๋“ค์–ด ๋ณต์žกํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ํฌํ•จ๋œ ๋กœ๋“œ๋œ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•จ์œผ๋กœ์จ ์‰ฝ๊ฒŒ ๋‹ฌ์„ฑ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Long-Polling๊ณผ ๊ฐ™์€ ํŠธ๋ฆญ์„ ๊ตฌํ˜„ํ•  ๋•Œ ๋‚ด๊ฐ€ ๋งํ•˜๋Š” ๊ฐ€๋Šฅ์„ฑ์„ ๊ณ ๋ คํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์š”์ปจ๋Œ€ ํŠธ๋ฆญ์˜ ๋ณธ์งˆ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. API ์ธก์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์ผ๋ถ€ ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ API๋กœ๋ถ€ํ„ฐ ๋ฐ›์•„์•ผ ํ•˜๋Š” ๋ฐ˜๋ฉด, API๋Š” ์–ด๋–ค ์ด์œ ๋กœ ์ด๋ฒคํŠธ๋ฅผ ๋ณด๊ณ ํ•  ์ˆ˜ ์—†๊ณ  ์ƒํƒœ๋งŒ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ์˜ˆ๋Š” WebSocket ์‹œ๋Œ€ ์ด์ „์ด๋‚˜ ์–ด๋–ค ์ด์œ ๋กœ ์ด ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅํ–ˆ์„ ๋•Œ HTTP ์œ„์— ๊ตฌ์ถ•๋œ ๋ชจ๋“  API์ž…๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ๋Š” HTTP ์„œ๋ฒ„์— ์š”์ฒญํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. HTTP ์„œ๋ฒ„ ์ž์ฒด๋Š” ํด๋ผ์ด์–ธํŠธ์™€์˜ ํ†ต์‹ ์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•œ ํ•ด๊ฒฐ์ฑ…์€ ํƒ€์ด๋จธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„๋ฅผ ํด๋งํ•˜๋Š” ๊ฒƒ์ด์ง€๋งŒ ์ด๋กœ ์ธํ•ด ์„œ๋ฒ„์— ์ถ”๊ฐ€ ๋กœ๋“œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  ํ‰๊ท  TimerInterval/2์— ์ถ”๊ฐ€ ์ง€์—ฐ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Long Polling์ด๋ผ๋Š” ํŠธ๋ฆญ์ด ๋ฐœ๋ช…๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ œํ•œ ์‹œ๊ฐ„์ด ๋งŒ๋ฃŒ๋˜๊ฑฐ๋‚˜ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ๊นŒ์ง€ ์„œ๋ฒ„์— ๋ณด๊ด€๋ฉ๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ฒ˜๋ฆฌ๋˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์š”์ฒญ์ด ๋‹ค์‹œ ์ „์†ก๋ฉ๋‹ˆ๋‹ค.

while(!eventOccures && !timeoutExceeded)  {

  CheckTimout();
  CheckEvent();
  Thread.Sleep(1);
}

๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๋Ÿฌํ•œ ์†”๋ฃจ์…˜์€ ์ด๋ฒคํŠธ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ํด๋ผ์ด์–ธํŠธ ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•˜์ž๋งˆ์ž ๋”์ฐํ•œ ๊ฒƒ์œผ๋กœ ํŒ๋ช…๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด... ์ด๋Ÿฌํ•œ ๊ฐ ํด๋ผ์ด์–ธํŠธ๋Š” ์ด๋ฒคํŠธ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์ „์ฒด ์Šค๋ ˆ๋“œ๋ฅผ ์ฐจ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ, ๊ทธ๋ฆฌ๊ณ  ์ด๋ฒคํŠธ๊ฐ€ ํŠธ๋ฆฌ๊ฑฐ๋  ๋•Œ ์ถ”๊ฐ€๋กœ 1ms์˜ ์ง€์—ฐ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ์ด๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š์ง€๋งŒ ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ๊ฐ€๋Šฅํ•œ ๊ฒƒ๋ณด๋‹ค ๋” ๋‚˜์˜๊ฒŒ ๋งŒ๋“œ๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? Thread.Sleep(1)์„ ์ œ๊ฑฐํ•˜๋ฉด ํ•˜๋‚˜์˜ ํ”„๋กœ์„ธ์„œ ์ฝ”์–ด๋ฅผ 100% ์œ ํœด ์ƒํƒœ๋กœ ๋กœ๋“œํ•˜์—ฌ ์“ธ๋ชจ ์—†๋Š” ์ฃผ๊ธฐ๋กœ ํšŒ์ „ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. TaskCompletionSource๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด ์ฝ”๋“œ๋ฅผ ์‰ฝ๊ฒŒ ๋‹ค์‹œ ๋งŒ๋“ค๊ณ  ์œ„์—์„œ ์‹๋ณ„๋œ ๋ชจ๋“  ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class LongPollingApi {

    private Dictionary<int, TaskCompletionSource<Msg>> tasks;

    public async Task<Msg> AcceptMessageAsync(int userId, int duration) {

        var cs = new TaskCompletionSource<Msg>();
        tasks[userId] = cs;
        await Task.WhenAny(Task.Delay(duration), cs.Task);
        return cs.Task.IsCompleted ? cs.Task.Result : null;
    }

    public void SendMessage(int userId, Msg m) {

        if (tasks.TryGetValue(userId, out var completionSource))
            completionSource.SetResult(m);
    }
}

์ด ์ฝ”๋“œ๋Š” ํ”„๋กœ๋•์…˜ ์ค€๋น„๊ฐ€ ๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉฐ ๋‹จ์ง€ ๋ฐ๋ชจ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ ์‚ฌ๋ก€์—์„œ ์ด๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์ตœ์†Œํ•œ ์•„๋ฌด๋„ ์˜ˆ์ƒํ•˜์ง€ ์•Š๋Š” ์‹œ๊ฐ„์— ๋ฉ”์‹œ์ง€๊ฐ€ ๋„์ฐฉํ•˜๋Š” ์ƒํ™ฉ์„ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ AsseptMessageAsync ๋ฉ”์„œ๋“œ๋Š” ์ด๋ฏธ ์™„๋ฃŒ๋œ ์ž‘์—…์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ๋ผ๋ฉด ValueTask ์‚ฌ์šฉ์„ ๊ณ ๋ คํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฉ”์‹œ์ง€์— ๋Œ€ํ•œ ์š”์ฒญ์„ ๋ฐ›์œผ๋ฉด TaskCompletionSource๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์ „์— ๋ฐฐ์น˜ํ•œ ๋‹ค์Œ ๋จผ์ € ์–ด๋–ค ์ผ์ด ์ผ์–ด๋‚ ์ง€ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค. ์ง€์ •๋œ ์‹œ๊ฐ„ ๊ฐ„๊ฒฉ์ด ๋งŒ๋ฃŒ๋˜๊ฑฐ๋‚˜ ๋ฉ”์‹œ์ง€๊ฐ€ ์ˆ˜์‹ ๋ฉ๋‹ˆ๋‹ค.

ValueTask: ์™œ ๊ทธ๋ฆฌ๊ณ  ์–ด๋–ป๊ฒŒ

ํ•ญ๋ณต ๋ฐ˜ํ™˜ ์—ฐ์‚ฐ์ž์™€ ๊ฐ™์€ async/await ์—ฐ์‚ฐ์ž๋Š” ๋ฉ”์„œ๋“œ์—์„œ ์ƒํƒœ ์‹œ์Šคํ…œ์„ ์ƒ์„ฑํ•˜๋ฉฐ ์ด๋Š” ๊ฑฐ์˜ ํ•ญ์ƒ ์ค‘์š”ํ•˜์ง€ ์•Š์ง€๋งŒ ๋“œ๋ฌผ๊ฒŒ ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ๋Š” ์ƒˆ ๊ฐœ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ๋Š” ์ •๋ง ์ž์ฃผ ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์„œ๋“œ์ผ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ดˆ๋‹น ์ˆ˜๋งŒ, ์ˆ˜์‹ญ๋งŒ ๊ฑด์˜ ํ˜ธ์ถœ์„ ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ๋Š” ์…ˆ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฉ”์„œ๋“œ๊ฐ€ ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ๋ชจ๋“  Wait ๋ฉ”์„œ๋“œ๋ฅผ ์šฐํšŒํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ž‘์„ฑ๋œ ๊ฒฝ์šฐ .NET์—์„œ๋Š” ์ด๋ฅผ ์ตœ์ ํ™”ํ•˜๋Š” ๋„๊ตฌ์ธ ValueTask ๊ตฌ์กฐ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋ช…ํ™•ํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ ์˜ˆ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ์บ์‹œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ์•ˆ์— ๋ช‡ ๊ฐ€์ง€ ๊ฐ’์ด ์žˆ์œผ๋ฉด ๊ฐ„๋‹จํžˆ ๋ฐ˜ํ™˜ํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋Š๋ฆฐ IO๋กœ ์ด๋™ํ•˜์—ฌ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ๋‚˜๋Š” ํ›„์ž๋ฅผ ๋น„๋™๊ธฐ์‹์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ „์ฒด ๋ฉ”์„œ๋“œ๊ฐ€ ๋น„๋™๊ธฐ์‹์œผ๋กœ ํŒ๋ช…๋˜์—ˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ฉ”์†Œ๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ํ™•์‹คํ•œ ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

public async Task<string> GetById(int id) {

    if (cache.TryGetValue(id, out string val))
        return val;
    return await RequestById(id);
}

์•ฝ๊ฐ„์˜ ์ตœ์ ํ™”๋ฅผ ์›ํ•˜๊ณ  Roslyn์ด ์ด ์ฝ”๋“œ๋ฅผ ์ปดํŒŒ์ผํ•  ๋•Œ ์ƒ์„ฑํ•  ๊ฒฐ๊ณผ์— ๋Œ€ํ•œ ์•ฝ๊ฐ„์˜ ๋‘๋ ค์›€ ๋•Œ๋ฌธ์— ์ด ์˜ˆ์ œ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‹ค์‹œ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

public Task<string> GetById(int id) {

    if (cache.TryGetValue(id, out string val))
        return Task.FromResult(val);
    return RequestById(id);
}

์‹ค์ œ๋กœ ์ด ๊ฒฝ์šฐ ์ตœ์ ์˜ ์†”๋ฃจ์…˜์€ ํ•ซ ํŒจ์Šค๋ฅผ ์ตœ์ ํ™”ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฆ‰, ๋ถˆํ•„์š”ํ•œ ํ• ๋‹น ๋ฐ GC ๋กœ๋“œ ์—†์ด ์‚ฌ์ „์—์„œ ๊ฐ’์„ ์–ป๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋“œ๋ฌธ ๊ฒฝ์šฐ์ง€๋งŒ ์—ฌ์ „ํžˆ ๋ฐ์ดํ„ฐ๋ฅผ ์œ„ํ•ด IO๋กœ ์ด๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. , ๋ชจ๋“  ๊ฒƒ์ด ์˜ˆ์ „ ๋ฐฉ์‹๋Œ€๋กœ ํ”Œ๋Ÿฌ์Šค/๋งˆ์ด๋„ˆ์Šค๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

public ValueTask<string> GetById(int id) {

    if (cache.TryGetValue(id, out string val))
        return new ValueTask<string>(val);
    return new ValueTask<string>(RequestById(id));
}

์ด ์ฝ”๋“œ ๋ถ€๋ถ„์„ ์ž์„ธํžˆ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์บ์‹œ์— ๊ฐ’์ด ์žˆ์œผ๋ฉด ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์‹ค์ œ ์ž‘์—…์ด ์˜๋ฏธ ์žˆ๋Š” ์ž‘์—…์œผ๋กœ ๋ž˜ํ•‘๋ฉ๋‹ˆ๋‹ค. ํ˜ธ์ถœ ์ฝ”๋“œ๋Š” ์ด ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋œ ๊ฒฝ๋กœ๋ฅผ ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. C# ๊ตฌ๋ฌธ ๊ด€์ ์—์„œ ValueTask๋Š” ์ด ๊ฒฝ์šฐ ์ผ๋ฐ˜ Task์™€ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

TaskSchedulers: ์ž‘์—… ์‹œ์ž‘ ์ „๋žต ๊ด€๋ฆฌ

๋‹ค์Œ์œผ๋กœ ๊ณ ๋ คํ•˜๊ณ  ์‹ถ์€ API๋Š” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. ์ž‘์—… ์Šค์ผ€์ค„๋Ÿฌ ๊ทธ๋ฆฌ๊ณ  ๊ทธ ํŒŒ์ƒ์ƒํ’ˆ. ์œ„์—์„œ TPL์—๋Š” ์Šค๋ ˆ๋“œ ์ „์ฒด์— ์ž‘์—…์„ ๋ฐฐํฌํ•˜๊ธฐ ์œ„ํ•œ ์ „๋žต์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค๊ณ  ์ด๋ฏธ ์–ธ๊ธ‰ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ „๋žต์€ TaskScheduler ํด๋ž˜์Šค์˜ ์ž์†์— ์ •์˜๋ฉ๋‹ˆ๋‹ค. ํ•„์š”ํ•œ ๊ฑฐ์˜ ๋ชจ๋“  ์ „๋žต์„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณ‘๋ ฌ ํ™•์žฅ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ, Microsoft์—์„œ ๊ฐœ๋ฐœํ–ˆ์ง€๋งŒ .NET์˜ ์ผ๋ถ€๋Š” ์•„๋‹ˆ์ง€๋งŒ Nuget ํŒจํ‚ค์ง€๋กœ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. ๊ทธ ์ค‘ ์ผ๋ถ€๋ฅผ ๊ฐ„๋‹จํžˆ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  • CurrentThreadTaskScheduler โ€” ํ˜„์žฌ ์Šค๋ ˆ๋“œ์—์„œ ์ž‘์—…์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • LimitedConcurrencyLevelTaskScheduler โ€” ์ƒ์„ฑ์ž์—์„œ ํ—ˆ์šฉ๋˜๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜ N์œผ๋กœ ๋™์‹œ์— ์‹คํ–‰๋˜๋Š” ์ž‘์—… ์ˆ˜๋ฅผ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค.
  • OrderedTaskScheduler โ€” LimitedConcurrencyLevelTaskScheduler(1)๋กœ ์ •์˜๋˜๋ฏ€๋กœ ์ž‘์—…์ด ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
  • ์ผํ›”์น˜๊ธฐTaskScheduler - ๊ตฌํ˜„ ์ผ์„ ํ›”์น˜๋Š” ๊ฒƒ ์ž‘์—… ๋ถ„๋ฐฐ์— ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค. ๋ณธ์งˆ์ ์œผ๋กœ ๋ณ„๋„์˜ ThreadPool์ž…๋‹ˆ๋‹ค. .NET์—์„œ ThreadPool์€ ๋ชจ๋“  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋Œ€ํ•ด ํ•˜๋‚˜์˜ ์ •์  ํด๋ž˜์Šค์ด๋ฏ€๋กœ ํ”„๋กœ๊ทธ๋žจ์˜ ํ•œ ๋ถ€๋ถ„์—์„œ ์˜ค๋ฒ„๋กœ๋“œ๋˜๊ฑฐ๋‚˜ ์ž˜๋ชป ์‚ฌ์šฉ๋˜๋ฉด ๋‹ค๋ฅธ ๋ถ€๋ถ„์—์„œ ๋ถ€์ž‘์šฉ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ๋”์šฑ์ด, ๊ทธ๋Ÿฌํ•œ ๊ฒฐํ•จ์˜ ์›์ธ์„ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์€ ๊ทนํžˆ ์–ด๋ ต๋‹ค. ์ €๊ฒƒ. ThreadPool ์‚ฌ์šฉ์ด ๊ณต๊ฒฉ์ ์ด๊ณ  ์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋กœ๊ทธ๋žจ ๋ถ€๋ถ„์—์„œ๋Š” ๋ณ„๋„์˜ WorkStealingTaskSchedulers๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋Œ€๊ธฐ ์ค‘์ธ ์ž‘์—… ์Šค์ผ€์ค„๋Ÿฌ โ€” ์šฐ์„ ์ˆœ์œ„ ๋Œ€๊ธฐ์—ด ๊ทœ์น™์— ๋”ฐ๋ผ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ThreadPerTask์Šค์ผ€์ค„๋Ÿฌ โ€” ์‹คํ–‰๋˜๋Š” ๊ฐ ์ž‘์—…์— ๋Œ€ํ•ด ๋ณ„๋„์˜ ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์™„๋ฃŒํ•˜๋Š” ๋ฐ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†์„ ์ •๋„๋กœ ์˜ค๋žœ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋Š” ์ž‘์—…์— ์œ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ž์„ธํ•˜๊ฒŒ ์ž˜ ๋‚˜์™€์žˆ์–ด์š” ๊ธฐ์‚ฌ Microsoft ๋ธ”๋กœ๊ทธ์˜ TaskSchedulers์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์„ธ์š”.

์ž‘์—…๊ณผ ๊ด€๋ จ๋œ ๋ชจ๋“  ๊ฒƒ์„ ํŽธ๋ฆฌํ•˜๊ฒŒ ๋””๋ฒ„๊น…ํ•˜๊ธฐ ์œ„ํ•ด Visual Studio์—๋Š” ์ž‘์—… ์ฐฝ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ฐฝ์—์„œ ์ž‘์—…์˜ ํ˜„์žฌ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๊ณ  ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ ์ฝ”๋“œ ์ค„๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

.NET: ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ ๋ฐ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์œ„ํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. 1 ๋ถ€

PLinq ๋ฐ Parallel ํด๋ž˜์Šค

Tasks ๋ฐ ์ด์— ๋Œ€ํ•ด ์–ธ๊ธ‰๋œ ๋ชจ๋“  ๊ฒƒ ์™ธ์—๋„ .NET์—๋Š” PLinq(Linq2Parallel) ๋ฐ Parallel ํด๋ž˜์Šค๋ผ๋Š” ๋‘ ๊ฐ€์ง€ ํฅ๋ฏธ๋กœ์šด ๋„๊ตฌ๊ฐ€ ๋” ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ๋Š” ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์—์„œ ๋ชจ๋“  Linq ์ž‘์—…์˜ ๋ณ‘๋ ฌ ์‹คํ–‰์„ ์•ฝ์†ํ•ฉ๋‹ˆ๋‹ค. ์Šค๋ ˆ๋“œ ์ˆ˜๋Š” WithDegreeOfParallelism ํ™•์žฅ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•ˆํƒ€๊น๊ฒŒ๋„ ๊ธฐ๋ณธ ๋ชจ๋“œ์˜ PLinq์—๋Š” ์ƒ๋‹นํ•œ ์†๋„ ํ–ฅ์ƒ์„ ์ œ๊ณตํ•  ๋งŒํผ ๋ฐ์ดํ„ฐ ์†Œ์Šค ๋‚ด๋ถ€์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด์— ์‹œ๋„ ๋น„์šฉ์€ ๋งค์šฐ ๋‚ฎ์Šต๋‹ˆ๋‹ค. ๋จผ์ € AsParallel ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. Linq ๋ฉ”์„œ๋“œ ์ฒด์ธ์„ ์‹คํ–‰ํ•˜๊ณ  ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ํŒŒํ‹ฐ์…˜ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ์†Œ์Šค์˜ ํŠน์„ฑ์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ PLinq์— ์ „๋‹ฌํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋” ์ฝ์–ด๋ณด์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ์—ฌ๊ธฐ์— ะธ ์—ฌ๊ธฐ์—.

Parallel ์ •์  ํด๋ž˜์Šค๋Š” Foreach ์ปฌ๋ ‰์…˜์„ ๋ณ‘๋ ฌ๋กœ ๋ฐ˜๋ณตํ•˜๊ณ , For ๋ฃจํ”„๋ฅผ ์‹คํ–‰ํ•˜๊ณ , ๋ณ‘๋ ฌ Invoke์—์„œ ์—ฌ๋Ÿฌ ๋Œ€๋ฆฌ์ž๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ณ„์‚ฐ์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ํ˜„์žฌ ์Šค๋ ˆ๋“œ์˜ ์‹คํ–‰์ด ์ค‘์ง€๋ฉ๋‹ˆ๋‹ค. ParallelOptions๋ฅผ ๋งˆ์ง€๋ง‰ ์ธ์ˆ˜๋กœ ์ „๋‹ฌํ•˜์—ฌ ์Šค๋ ˆ๋“œ ์ˆ˜๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ TaskScheduler ๋ฐ CancellationToken์„ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์กฐ์‚ฌ ๊ฒฐ๊ณผ

๋ณด๊ณ ์„œ ์ž๋ฃŒ์™€ ์ดํ›„ ์ž‘์—…ํ•˜๋ฉด์„œ ์ˆ˜์ง‘ํ•œ ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ด ๊ธ€์„ ์“ฐ๊ธฐ ์‹œ์ž‘ํ–ˆ์„ ๋•Œ, ์ด๋ ‡๊ฒŒ ๋งŽ์€ ๋‚ด์šฉ์ด ์žˆ์„ ๊ฒƒ์ด๋ผ๊ณ ๋Š” ์˜ˆ์ƒํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ๋‚ด๊ฐ€ ์ด ๊ธ€์„ ์“ฐ๊ณ  ์žˆ๋Š” ํ…์ŠคํŠธ ํŽธ์ง‘๊ธฐ๊ฐ€ 15ํŽ˜์ด์ง€๊ฐ€ ์‚ฌ๋ผ์กŒ๋‹ค๊ณ  ๋น„๋‚œํ•˜๋ฉด์„œ ์ค‘๊ฐ„ ๊ฒฐ๊ณผ๋ฅผ ์š”์•ฝํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํŠธ๋ฆญ, API, ์‹œ๊ฐ์  ๋„๊ตฌ ๋ฐ ํ•จ์ •์€ ๋‹ค์Œ ๊ธฐ์‚ฌ์—์„œ ๋‹ค๋ฃจ๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก  :

  • ์ตœ์‹  PC์˜ ๋ฆฌ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์Šค๋ ˆ๋“œ, ๋น„๋™๊ธฐ ๋ฐ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ๋„๊ตฌ๋ฅผ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • .NET์—๋Š” ์ด๋Ÿฌํ•œ ๋ชฉ์ ์„ ์œ„ํ•œ ๋‹ค์–‘ํ•œ ๋„๊ตฌ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ชจ๋“  API๊ฐ€ ํ•œ๊บผ๋ฒˆ์— ๋‚˜ํƒ€๋‚˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ ˆ๊ฑฐ์‹œ API๋ฅผ ์ข…์ข… ์ฐพ์„ ์ˆ˜ ์žˆ์ง€๋งŒ, ๋งŽ์€ ๋…ธ๋ ฅ์„ ๋“ค์ด์ง€ ์•Š๊ณ ๋„ ์˜ค๋ž˜๋œ API๋ฅผ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • .NET์—์„œ ์Šค๋ ˆ๋“œ ์ž‘์—…์€ Thread ๋ฐ ThreadPool ํด๋ž˜์Šค๋กœ ํ‘œํ˜„๋ฉ๋‹ˆ๋‹ค.
  • Thread.Abort, Thread.Interrupt ๋ฐ Win32 API TerminateThread ๋ฉ”์„œ๋“œ๋Š” ์œ„ํ—˜ํ•˜๋ฏ€๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  CancellationToken ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ข‹์Šต๋‹ˆ๋‹ค.
  • ํ๋ฆ„์€ ๊ท€์ค‘ํ•œ ์ž์›์ด๋ฉฐ ๊ณต๊ธ‰์ด ์ œํ•œ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์Šค๋ ˆ๋“œ๊ฐ€ ์ด๋ฒคํŠธ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š๋ผ ๋ฐ”์œ ์ƒํ™ฉ์€ ํ”ผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด TaskCompletionSource ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ํŽธ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ ๋ฐ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์œ„ํ•œ ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•˜๊ณ  ์ง„๋ณด๋œ .NET ๋„๊ตฌ๋Š” ์ž‘์—…์ž…๋‹ˆ๋‹ค.
  • C# async/await ์—ฐ์‚ฐ์ž๋Š” ๋น„์ฐจ๋‹จ ๋Œ€๊ธฐ ๊ฐœ๋…์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  • TaskScheduler ํŒŒ์ƒ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์Šค๋ ˆ๋“œ ๊ฐ„ ์ž‘์—… ๋ฐฐํฌ๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ValueTask ๊ตฌ์กฐ๋Š” ํ•ซ ํŒจ์Šค ๋ฐ ๋ฉ”๋ชจ๋ฆฌ ํŠธ๋ž˜ํ”ฝ์„ ์ตœ์ ํ™”ํ•˜๋Š” ๋ฐ ์œ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Visual Studio์˜ ์ž‘์—… ๋ฐ ์Šค๋ ˆ๋“œ ์ฐฝ์€ ๋‹ค์ค‘ ์Šค๋ ˆ๋“œ ๋˜๋Š” ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ๋””๋ฒ„๊น…ํ•˜๋Š” ๋ฐ ์œ ์šฉํ•œ ๋งŽ์€ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  • PLinq๋Š” ๋ฉ‹์ง„ ๋„๊ตฌ์ด์ง€๋งŒ ๋ฐ์ดํ„ฐ ์†Œ์Šค์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์ง€๋งŒ ํŒŒํ‹ฐ์…”๋‹ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ณ„์† ๋  ...

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€