์ง„์งœ ๐Ÿถ์‰ฝ๊ฒŒ Isolate ์ ์šฉํ•˜๊ธฐ

Ximya(์‹ฌ์•ผ)ยท2023๋…„ 5์›” 29์ผ
8

Plotz ๊ฐœ๋ฐœ์ผ์ง€

๋ชฉ๋ก ๋ณด๊ธฐ
8/12

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

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” ์•„์ฃผ ์‰ฝ๊ฒŒ Flutter ํ”„๋กœ์ ํŠธ์— Isolate์„ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋‹ค๋ฃจ์–ด ๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๋ณต์žกํ•œ ์„ค๋ช…์€ ์ตœ๋Œ€ ๋ฐฐ์ œํ•˜๊ณ  ํ•ต์‹ฌ ๋‚ด์šฉ๋งŒ ์„ค๋ช…ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๋ชฉ์ฐจ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. Isloate ์ด๋ž€?
  2. ์–ธ์ œ ๊ทธ๋ฆฌ๊ณ  ์™œ Isolate์„ ์‚ฌ์šฉํ• ๊นŒ?
  3. ์‰ฝ๊ณ  ์œ ์—ฐํ•˜๊ฒŒ Isolate์„ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

Isolate์— ๊ตฌ์ฒด์ ์ธ ์ž‘๋™๋ฐฉ์‹์— ๋Œ€ํ•ด ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๊ณ  ์žˆ๋”๋ผ๋„ ๋ฐ”๋กœ ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ชจ๋“ˆํ™”๋œ ์ฝ”๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ƒ์„ธ ๊ฐœ๋…์ด ๊ถ๊ธˆํ•˜์‹œ๋ฉด Flutter ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

++
https://pub.dev/packages/easy_isolate_mixin
์ตœ๊ทผ์— Isolate์„ ์‰ฝ๊ฒŒ ๋„์™€์ฃผ๋Š” ํŒจํ‚ค์ง€๋ฅผ ๋ฐฐํฌํ–ˆ์Šต๋‹ˆ๋‹ค!


Isloate ์ด๋ž€?

๋จผ์ € Isolate ๊ฐœ๋…์„ ๊ฐ€๋ณ๊ฒŒ ์งš๊ณ  ๋„˜์–ด๊ฐ‘์‹œ๋‹ค.

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

๊ณต์‹๋ฌธ์„œ์— ์„ค๋ช…๋˜์–ด ์žˆ๋Š” ๊ธ€ ์ž…๋‹ˆ๋‹ค. ์กฐ๊ธˆ ๋ณต์žกํ•˜์ฃ ?

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

๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์™€ Isolate์˜ ์ฐจ์ด

์ด๋•Œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ(async-await)์™€ Isolate ๋ชจ๋‘ ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์ง€์›ํ•œ๋‹ค๋Š” ๊ณตํ†ต์ ์ด ์žˆ์ง€๋งŒ ๋ช…ํ™•ํ•œ ์ฐจ์ด์ ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ถ€๋ถ„์ด Isolate๋ฅผ ์ดํ•ดํ•˜๋Š”๋ฐ, ์žˆ์–ด์„œ ๊ต‰์žฅํžˆ ์ค‘์š”ํ•œ ๊ฐœ๋…์ธ๋ฐ์š”. ์Šคํƒ€ํฌ๋ž˜ํ”„ํŠธ ๊ฒŒ์ž„์œผ๋กœ ๋น„์œ ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

1. ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์™€ ํ…Œ๋ž€

๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ†ตํ•ด ๋™์‹œ์ ์œผ๋กœ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•œ๋‹ค๋Š” ๊ฒƒ์€ ํ…Œ๋ž€์˜ SCV๊ฐ€ 2๊ฐœ์˜ ๊ฑด๋ฌผ์„ ์ง“๋Š” ์ƒํ™ฉ์ผ ๋•Œ, ๊ฑด๋ฌผ์„ ์กฐ๊ธˆ์”ฉ ๋ฒˆ๊ฐˆ์•„ ๊ฐ€๋ฉด์„œ ์ง“๋Š” ์ƒํ™ฉ์ด๋ผ๊ณ  ์ดํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(SCV๋Š” ๊ฑด๋ฌผ์„ ์ง“๋Š” ๊ณผ์ •์„ ์ค‘๋‹จ ๋ฐ ์žฌ๊ฐœํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด ๊ณ ์ฆ๋˜์—ˆ์Šต๋‹ˆ๋‹ค)
์—ฌ๊ธฐ์„œ ๊ฑด๋ฌผ์€ ํ•˜๋‚˜์˜ ์ž‘์—… ๋‹จ์œ„์ด๊ณ  ๊ฑด๋ฌผ์„ ์ง“๋Š” SCV๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์Šค๋ ˆ๋“œ์ธ ์…ˆ์ด์ฃ .

2. isolate๊ณผ ํ”„๋กœํ† ์Šค


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

์ฆ‰, ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๋ฐฉ์‹๊ณผ ๋‹ค๋ฅด๊ฒŒ Isolate์€ ๋…๋ฆฝ๋œ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์„ ๊ฐ€์ง€๊ณ  ๋ณ‘๋ ฌ ๋ฐ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํŠน์ง•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, ์—ฌ๋Ÿฌ ๊ฐœ์˜ Isolate์ด ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋Š” ๊ตฌ์กฐ์ด๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

๊ฑด๋ฌผ์„ ์ง“๋Š” ํ–‰์œ„ : ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น
๊ฑด๋ฌผ : ํ”„๋กœ์„ธ์Šค
์œ ๋‹› : ์Šค๋ ˆ๋“œ
ํ”„๋กœํ† ์Šค์˜ ํ”Œ๋ผ์ฆˆ๋งˆ ํ•„๋“œ : isolate(event loop)


์–ธ์ œ ๊ทธ๋ฆฌ๊ณ  ์™œ Isolate์„ ์‚ฌ์šฉํ• ๊นŒ?

์ œ ๊ฒฝํ—˜์ƒ ๋Œ€๋ถ€๋ถ„์€ Isolate์„ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์—์„œ๋„ ์ถฉ๋ถ„ํžˆ ์—ญํ• ์„ ํ•ด๋‚ผ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ์˜ˆ์™ธ Ioslate ๋„์ž…์„ ๊ณ ๋ คํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ๋Œ€์šฉ๋Ÿ‰ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ
    ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ด๋ฏธ์ง€๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š”๋ฐ ์ƒ๊ฐ๋ณด๋‹ค ๋ฆฌ์†Œ์Šค๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๊ณ ํ™”์งˆ ์ด๋ฏธ์ง€๋ฅผ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ Isolate์„ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ์ข‹์Šต๋‹ˆ๋‹ค
  1. ๋Œ€๊ทœ๋ชจ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ

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

  2. ๋ณต์žกํ•œ ๊ณ„์‚ฐ
    ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋ณต์žกํ•œ ๊ณ„์‚ฐ ์ž‘์—…์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋„ Isolate์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ๋ฌด๊ฑฐ์šด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” loop๋ฌธ ์—ฌ๋Ÿฌ ๋ฒˆ ๋ฐ˜๋ณต๋œ๋‹ค๋ฉด Isolate ๋„์ž…์„ ๊ณ ๋ คํ•ด ๋ณด์„ธ์š”.

์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๊ฒฝ์šฐ ์ด์™ธ์—๋„ Frame Drop, ์ฆ‰ ๋ฒ„๋ฒ…๊ฑฐ๋ฆผ ํ˜„์ƒ์ด ๋ณด์ธ๋‹ค๊ณ  ์›์ธ์„ ํŒŒ์•…ํ•˜๊ณ  Isolate์„ ์ ์šฉํ•ด๋„ ๋ฌด๋ฐฉํ•ฉ๋‹ˆ๋‹ค. ์š”์•ฝํ•˜๋ฉด UI ์Šค๋ ˆ๋“œ์˜ ๋ถ€ํ•˜๋ฅผ ์ค„์ด๊ณ  ์•ฑ์˜ ์ „์ฒด์ ์ธ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒํ•˜๊ธฐ ์œ„ํ•ด Isolate์„ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


์‰ฝ๊ณ  ์œ ์—ฐํ•˜๊ฒŒ Isolate์„ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

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

import 'dart:async';
import 'dart:collection';
import 'dart:isolate';
import 'package:flutter/services.dart';

// Isolate๋ฅผ ๋‹ค๋ฃจ๋Š” mixin ํด๋ž˜์Šค
mixin IsolateHelperMixin {
  // ๋™์‹œ์— ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” Isolate์˜ ์ตœ๋Œ€ ๊ฐœ์ˆ˜ ์„ค์ •
  static const int _maxIsolates = 5;

  // ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ Isolate์˜ ๊ฐœ์ˆ˜๋ฅผ ์ถ”์ 
  int _currentIsolates = 0;

  // ๋ณด๋ฅ˜ ์ค‘์ธ ์ž‘์—…์„ ์ €์žฅํ•˜๋Š” ํ
  final Queue<Function> _taskQueue = Queue();

  // Isolate๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜, ๋งŒ์•ฝ ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ Isolate์˜ ๊ฐœ์ˆ˜๊ฐ€ ์ตœ๋Œ€์น˜์— ๋„๋‹ฌํ•œ ๊ฒฝ์šฐ ํ์— ์ž‘์—…์„ ์ถ”๊ฐ€
  Future<T> loadWithIsolate<T>(Future<T> Function() function) async {
    if (_currentIsolates < _maxIsolates) {
      _currentIsolates++;
      return _executeIsolate(function);
    } else {
      final completer = Completer<T>();
      _taskQueue.add(() async {
        final result = await _executeIsolate(function);
        completer.complete(result);
      });
      return completer.future;
    }
  }

  // ์ƒˆ๋กœ์šด Isolate๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ฃผ์–ด์ง„ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰
  Future<T> _executeIsolate<T>(Future<T> Function() function) async {
    final ReceivePort receivePort = ReceivePort();
    final RootIsolateToken rootIsolateToken = RootIsolateToken.instance!;

    final isolate = await Isolate.spawn(
      _isolateEntry,
      _IsolateEntryPayload(
        function: function,
        sendPort: receivePort.sendPort,
        rootIsolateToken: rootIsolateToken,
      ),
    );

    // Isolate์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›๊ณ , ์ด Isolate๋ฅผ ์ข…๋ฃŒํ•œ ํ›„, ํ์—์„œ ๋‹ค์Œ ์ž‘์—…์„ ์‹คํ–‰
    return receivePort.first.then(
          (dynamic data) {
        _currentIsolates--;
        _runNextTask();
        if (data is T) {
          isolate.kill(priority: Isolate.immediate);
          return data;
        } else {
          isolate.kill(priority: Isolate.immediate);
          throw data;
        }
      },
    );
  }

  // ํ์—์„œ ๋‹ค์Œ ์ž‘์—…์„ ๊บผ๋‚ด์–ด ์‹คํ–‰
  void _runNextTask() {
    if (_taskQueue.isNotEmpty) {
      final nextTask = _taskQueue.removeFirst();
      nextTask();
    }
  }
}

// Isolate์—์„œ ์‹คํ–‰๋˜๋Š” ํ•จ์ˆ˜
Future<void> _isolateEntry(_IsolateEntryPayload payload) async {
  final Function function = payload.function;

  try {
    BackgroundIsolateBinaryMessenger.ensureInitialized(
      payload.rootIsolateToken,
    );
  } on MissingPluginException catch (e) {
    print(e.toString());
    return Future.error(e.toString());
  }

  // payload๋กœ ์ „๋‹ฌ๋ฐ›์€ ํ•จ์ˆ˜ ์‹คํ–‰ ํ›„ ๊ฒฐ๊ณผ๋ฅผ sendPort๋ฅผ ํ†ตํ•ด ๋ฉ”์ธ Isolate๋กœ ๋ณด๋ƒ„
  final result = await function();
  payload.sendPort.send(result);
}

// Isolate ์ƒ์„ฑ ์‹œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด๋Š” ํด๋ž˜์Šค
class _IsolateEntryPayload {
  const _IsolateEntryPayload({
    required this.function,
    required this.sendPort,
    required this.rootIsolateToken,
  });

  final Future<dynamic> Function() function; // Isolate์—์„œ ์‹คํ–‰ํ•  ํ•จ์ˆ˜
  final SendPort sendPort; // ๋ฉ”์ธ Isolate๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๊ธฐ ์œ„ํ•œ SendPort
  final RootIsolateToken rootIsolateToken; // Isolate๊ฐ„ ํ†ต์‹ ์„ ์œ„ํ•œ ํ† ํฐ
}

์ ์šฉ ์˜ˆ์‹œ:

// Repository ๋ ˆ์ด์–ด์—์„œ IsolateHelperMixin์„ ์ ์šฉ

// ์œ ์ € ๋ ˆํฌ์ง€ํ† ๋ฆฌ ํด๋ž˜์Šค
class UserRepository with IsolateHelperMixin {
  UserRepository(this._api);

  // Isolate ์ ์šฉ ๋ฒ„์ „
  Future<ProfileImgRes> loadUserProfileImg() async =>
      loadWithIsolate(() => _api.loadUserProfileImg());

  // Isolate ์ ์šฉ์ด ์•ˆ๋œ ๋ฒ„์ „
  Future<UserInfo> loadUserDetailInfo() async => _api.loadUserDetailInfo();
}

// ์ฝ˜ํ…์ธ  ๋ ˆํฌ์ง€ํ† ๋ฆฌ ํด๋ž˜์Šค
class ContentRepository with IsolateHelperMixin {
  ContentRepository(this._api);

  // Isolate ์ ์šฉ ๋ฒ„์ „
  Future<ContentImg> loadContentImg() async =>
      loadWithIsolate(() => _api.loadContentImg());

  // Isolate ์ ์šฉ์ด ์•ˆ๋œ ๋ฒ„์ „
  Future<ContentInfo> loadContentInfo() async => () => _api.loadContentInfo();
}

// ์‚ฌ์šฉ์ž ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
final userRepository = UserRepository(UserApi());
final user = await userRepository.getUserDetails();
print(user);
// ๋ฉ”์ธ ํ•จ์ˆ˜์—์„œ ํ•„์š”ํ•œ ๊ฐ’๋“ค์„ ์ดˆ๊ธฐํ™” ํ•ด์ค˜์•ผ ํ•จ

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // NOTE : Isolate ํ† ํฐ ์ƒ์„ฑ ๋ฐ ์ดˆ๊ธฐํ™”
  final RootIsolateToken rootIsolateToken = RootIsolateToken.instance!;
  BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken);

  runApp(const MyApp());
}

ํŠน์ง•

1. Future<T> Function() ํƒ€์ž…์„ ์ธ์ž๋กœ ๋ฐ›๋Š” ๋ฉ”์†Œ๋“œ

Isolate์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์€ Future<T> ๋ฉ”์†Œ๋“œ๋ฅผ ์ธ์ž๋กœ ๋ฐ›์œผ๋ฉด ๊ฐ„ํŽธํ•˜๊ฒŒ Isolate์„ ๊ธฐ๋Šฅ์„ ์‹คํ–‰์‹œํ‚ฌ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ์˜ ์œ ์—ฐ์„ฑ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

// _api.loadContentImg() <-- ๊ธฐ์กด ๋ฉ”์†Œ๋“œ

Future<ContentImg> loadContentImg() async =>
     loadWithIsolate(() => _api.loadContentImg());

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

์š”์•ฝํ•˜์ž๋ฉด, Future Function() ํƒ€์ž…์„ ์ธ์ž๋กœ ๋ฐ›์Œ์œผ๋กœ์จ ๋‹ค์–‘ํ•œ ๋น„๋™๊ธฐ ์ž‘์—…์— ๋Œ€ํ•ด ๊ฐ„๊ฒฐํ•˜๊ณ  ์œ ์—ฐํ•œ ์ฝ”๋“œ ์ž‘์„ฑ์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ค๋ฉฐ, ์œ ์ง€ ๊ด€๋ฆฌ๋ฅผ ์šฉ์ดํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

2. mixin ํด๋ž˜์Šค ๊ธฐ๋ฐ˜์˜ Isolate

Isolate์„ mixin ํด๋ž˜์Šค๋กœ ๊ด€๋ฆฌํ•˜๋Š” ์ด์œ ๋Š” ํฌ๊ฒŒ 3๊ฐ€์ง€ ์žฅ์ ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

  1. ์žฌ์‚ฌ์šฉ์„ฑ
    Isolate ๊ด€๋ฆฌ ์ฝ”๋“œ๋ฅผ ์—ฌ๋Ÿฌ ํด๋ž˜์Šค์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” DRY(Don't Repeat Yourself)์›์น™์„ ๋”ฐ๋ฅด๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ์œ„ ์ฝ”๋“œ์—์„œ UserRepository์™€ ContentRepository ํด๋ž˜์Šค์— ๊ณตํ†ต์ ์œผ๋กœ IsolateHelperMixin ํด๋ž˜์Šค๊ฐ€ ๋ฏน์Šค์ธ๋˜์–ด isolate๊ธฐ๋Šฅ ๋™์ผํ•˜๊ฒŒ ์ˆ˜ํ–‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค

  2. ์„ค๊ณ„์˜ ์œ ์—ฐ์„ฑ
    mixin์„ ์ด์šฉํ•˜๋ฉด ํด๋ž˜์Šค ๋‚ด์—์„œ ๊ด€๋ฆฌ๋˜๋Š” ๋ฉ”์†Œ๋“œ์— ์„ ํƒ์ ์œผ๋กœ isolate์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด UserRpeository์˜ loadUserProfileImg ๋ฉ”์†Œ๋“œ๋Š” Isolate์ด ์ ์šฉ๋˜์—ˆ์ง€๋งŒ loadUserDetailInfo ๋ฉ”์†Œ๋“œ๋Š” ์„ ํƒ์ ์œผ๋กœ Ioslate์„ ์ ์šฉํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. mixin ๋•๋ถ„์— ์ด๋ ‡๊ฒŒ ์œ ์—ฐํ•œ ๊ตฌ์กฐ๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

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

3. Isolate ์ตœ๋Œ€ ๊ฐœ์ˆ˜ ์ œํ•œ

loadWithIsolate ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ์ตœ๋Œ€ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ Isolate์˜ ๊ฐœ์ˆ˜๋ฅผ ์ œํ•œํ•˜๋Š” ๋กœ์ง์ด ๋“ค์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์‹œ์Šคํ…œ ๋ฆฌ์†Œ์Šค๋ฅผ ํšจ์œจ์ ์œผ๋กœ ํ™œ์šฉํ•˜๊ณ , ๋„ˆ๋ฌด ๋งŽ์€ Isolate์ด ๋™์‹œ์— ์‹คํ–‰๋˜์–ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์„ฑ๋Šฅ ์ €ํ•˜๋‚˜ ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.


๋งˆ๋ฌด๋ฆฌ

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” Isolate์„ ์‰ฝ๊ณ  ์œ ์—ฐํ•˜๊ฒŒ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์œ„์—์„œ ์ž ๊น ์–ธ๊ธ‰ํ–ˆ์ง€๋งŒ, ๋Œ€๋ถ€๋ถ„์€ Isolate์„ ์‚ฌ์šฉํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์˜คํžˆ๋ ค Isolate์„ ๋‚จ์šฉํ•˜๋ฉด ์ „์ฒด์ ์œผ๋กœ ์•ฑ ์„ฑ๋Šฅ์— ์•ˆ์ข‹์€ ์˜ํ–ฅ์„ ์ฃผ๊ธฐ ๋•Œ๋ฌธ์ด์ฃ .

๊ทธ๋ž˜์„œ ์ ์ ˆํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. Ioslate์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ํฌ์ŠคํŒ…์—์„œ ์ œ๊ณต๋œ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ์‰ฝ๊ณ  ์œ ์—ฐํ•˜๊ฒŒ Ioslate์„ ์ ์šฉํ•ด ๋ณด์„ธ์š” ๐Ÿ˜€

profile
https://medium.com/@ximya

3๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2023๋…„ 10์›” 25์ผ

๊ธ€ ๋„ˆ๋ฌด ์ž˜ ๋ดค์Šต๋‹ˆ๋‹ค!!

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
5์ผ ์ „

์—„์ฒญ๋‚œ ๊ณ ์ˆ˜ ใ„ทใ„ท

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ