๐ŸŽฎ Unity Study/C#

[C#] ๋™๊ธฐ/๋น„๋™๊ธฐ (feat. Coroutine, Task, async/await)

ibelieveinme 2023. 8. 16. 23:08
728x90

*๋™๊ธฐ: ์ผ์„ ์ฃผ๊ณ  ๊ทธ ์ผ์ด ๋๋‚ ๋•Œ๊นŒ์ง€ ์•„๋ฌด๊ฒƒ๋„ ์•ˆํ•˜๊ณ  ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒƒ. ex) ๋งคํ‘œ์†Œ ์ค„

*๋น„๋™๊ธฐ: ์ผ์„ ์ค€ ํ›„ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋‚ด ์ผ์„ ํ•˜๋Š” ๊ฒƒ. ex) ์ปคํ”ผ์ˆ ์ง„๋™๋ฒจ


#๋™๊ธฐ์‹ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์˜ˆ์‹œ

using System;

public class TestClass {

    static void Main(string[] args) {
        PrintNumber();
        PrintStart();

        Console.ReadKey();
    }

    private static void PrintNumber() {
        for(int i = 0; i < 10; i++) {
            Console.WriteLine(i);
        }
    }

    private static void PrintStart() {
        for (int i = 0; i < 10; i++) {
            Console.WriteLine("*");
        }
    }
}
0
1
2
3
4
...
*
*
*
*
...

PrintNumber(), PrintStart() ํ•จ์ˆ˜๊ฐ€ ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰๋œ๋‹ค.

 

#๋น„๋™๊ธฐ์‹ ํ”„๋กœ๊ทธ๋ž˜๋ฐ(Thread)์˜ ์˜ˆ์‹œ

using System;
using System.Threading;

public class TestClass {

    static void Main(string[] args) {

        var thread1 = new Thread(PrintNumber);
        thread1.Start();

        var thread2 = new Thread(PrintStart);
        thread2.Start();

        Console.ReadKey();
    }

    private static void PrintNumber() {
        for(int i = 0; i < 10; i++) {
            Console.WriteLine(i);
        }
    }

    private static void PrintStart() {
        for (int i = 0; i < 10; i++) {
            Console.WriteLine("*");
        }
    }
}
0
*
1
*
2
*
...

PrintNumber(), PrintStart() ํ•จ์ˆ˜๊ฐ€ ๋™์‹œ์— ์‹คํ–‰๋œ๋‹ค.

 

*Thread์˜ ๋ฌธ์ œ์ 

Thread ๋Š” return ๊ฐ’์ด ์—†๋Š” class ์ด๋‹ค. (๊ธฐ๋Šฅ์ด ๋งค์šฐ ํ•œ์ •์ )

Thread ์˜ ์ข…๋ฃŒ์‹œ์ ์„ ์•Œ ์ˆ˜ ์—†๋‹ค.

Thread ๋Š” ์ทจ์†Œ/์˜ˆ์™ธ์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์—†๋‹ค.

Thread๋Š” 1MB ๋กœ ์ƒ๋‹นํžˆ ๋ฌด๊ฑฐ์šด ๊ฐ์ฒด์ด๋‹ค.

์ƒ์„ฑํ•  ๋•Œ๋งˆ๋‹ค ์ฐธ์กฐ๋˜์–ด ์žˆ๋Š” ๋ชจ๋“  DLL ์„ ๋Œ๋ฉด์„œ ๊ณต๊ฐ„ํ• ๋‹น์„ ์š”์ฒญํ•œ๋‹ค. 

 

Thread์˜ ๋ฌธ์ œ์ ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋‚˜์˜จ๊ฒŒ Task !

Thread pool๋กœ ๋ถ€ํ„ฐ Thread๋ฅผ ๊ฐ€์ ธ์™€์„œ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

Task Chain ๊ฐœ๋…์ด ๋„์ž…๋˜์–ด ์—ฌ๋Ÿฌ Thread ๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ๋™์ž‘ํ•˜๊ฒŒ ํ•œ๋‹ค.

 

Task ๋ฐ˜ํ™˜๊ฐ’ ์•ž์— async ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์ธ๋‹ค.

๋Œ€๊ธฐ๊ฐ€ ํ•„์š”ํ•˜๋ฉด(๋™๊ธฐ์ฒ˜๋Ÿผ) await ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ž. ๋ฉ”์†Œ๋“œ๋Š” ์ž ์‹œ ์ค‘๋‹จ๋˜๊ณ  ํ”„๋กœ๊ทธ๋žจ์€ ๊ณ„์† ์ง„ํ–‰ํ•œ๋‹ค.

Task ์˜ ๋ฐ˜ํ™˜๊ฐ’์€ void, Task, Task<T> ์…‹ ์ค‘์— ํ•˜๋‚˜๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

# Task ์˜ˆ์‹œ 1) Action

public class TestClass : MonoBehaviour {

    private void Start() {
        Task task1 = new Task(PrintNumber);
        task1.Start();

        Task task2 = new Task(PrintStart);
        task2.Start();
    }

    private void PrintNumber() {
        for (int i = 0; i < 10; i++) {
            Debug.Log(i);
        }
    }

    private void PrintStart() {
        for (int i = 0; i < 10; i++) {
            Debug.Log("*");
        }
    }
}

Thread ๋ฅผ Task ๋กœ๋งŒ ๋ฐ”๊ฟจ๊ณ  ๋น„๋™๊ธฐ๋กœ ์ž˜ ์‹คํ–‰๋˜๋Š” ๋ชจ์Šต์ด๋‹ค.

public class TestClass : MonoBehaviour {

    private void Start() {
        Task.Run(PrintNumber);
        Task.Run(PrintStart);
    }

    private void PrintNumber() {
        for (int i = 0; i < 10; i++) {
            Debug.Log(i);
        }
    }

    private void PrintStart() {
        for (int i = 0; i < 10; i++) {
            Debug.Log("*");
        }
    }
}

์ธ์ž๊ฐ€ ์—†๋Š” ๋ฉ”์†Œ๋“œ๋ผ๋ฉด Task.Run(ํ•จ์ˆ˜๋ช…) ๋กœ ๊ฐ„๋‹จํžˆ ๋ถ€๋ฅผ ์ˆ˜๋„ ์žˆ๋‹ค.

public class TestClass : MonoBehaviour {

    private void Start() {
        Task.Run(() => PrintNumber());
        Task.Run(() => PrintStart());
    }

    private void PrintNumber() {
        for (int i = 0; i < 5; i++) {
            Debug.Log(i);
        }
    }

    private void PrintStart() {
        for (int i = 0; i < 5; i++) {
            Debug.Log("*");
        }
    }
}

๋žŒ๋‹ค์‹ ํ‘œํ˜„์€ ์œ„์™€ ๊ฐ™๋‹ค.

 

# Task ์˜ˆ์‹œ 2)  Task<T>

public class TestClass : MonoBehaviour {

    private void Start() {

        Task<int> task = new Task<int>(GetResult);
        task.Start();
        Debug.Log(task.Result); // ๊ฒฐ๊ณผ๊ฐ’ ๋Œ€๊ธฐ

        Task.Run(() => PrintNumber());
        Task.Run(() => PrintStar());
    }

    private void PrintNumber() {
        for (int i = 0; i < 5; i++) {
            Debug.Log(i);
        }
    }

    private void PrintStar() {
        for (int i = 0; i < 5; i++) {
            Debug.Log("*");
        }
    }

    private int GetResult() {
        for (int i = 0; i < 5; i++) {
            Debug.Log("/");
        }
        return 1;
    }
}

Task ๋กœ ๋„ฃ์€ ํ•จ์ˆ˜์˜ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š”๋ฐ task.Result ๊ตฌ๋ฌธ์€ ํ•ด๋‹น ์œ„์น˜์—์„œ ๊ฒฐ๊ณผ๊ฐ’์„ ๋Œ€๊ธฐํ•˜๊ฒŒ ๋œ๋‹ค.

ํ•ด๋‹น ํ•จ์ˆ˜ ์•ˆ์— ์ดํ›„ ํ–‰๋™์„ ๋„ฃ์œผ๋ฉด ๋น„๋™๊ธฐ์‹์œผ๋กœ ์ž˜ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์„๋“ฏ.

 

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading.Tasks;


public class Example : MonoBehaviour
{
    int number = 0;

    private void Start() {
        Task.Run(() => Testing());
    }

    async Task Testing() {
        await Task.Run(() => {
            while(number < 50) {
                number++;
            }
        });
        await Task.Delay(5000);
    }
}

Task ๋Š” ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๋Š” ๋น„๋™๊ธฐ ์ž‘์—…,

Task<TResult>๋Š” ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์ด๋‹ค.

 

๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌ๋˜์–ด์•ผ ํ•˜๋Š” ๋ถ€๋ถ„์— await ์—ฐ์‚ฐ์ž๋ฅผ ์ ์šฉํ•ด์ค€๋‹ค.

 

 

P.S) Coroutine ์€ ๋น„๋™๊ธฐ์ผ๊นŒ?

ํ”„๋ ˆ์ž„์˜ ํ๋ฆ„์„ ๋„˜๊ฒจ์ฃผ๋ฉฐ ์™„๋ฒฝํ•œ ๋น„๋™๊ธฐ ๋ฐฉ์‹์ด ์•„๋‹Œ ํ”„๋ ˆ์ž„์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

null, WaitForSecond, WaitForFixedUpdate, WaitForEndOfFrame, WaitUntil ๋“ฑ ์‹œ๊ฐ„์— ๋”ฐ๋ผ ๋Œ€๊ธฐํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

async/await ์™€์˜ ์ฐจ์ด์ ์€ return ๊ฐ’์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋ƒ ์—†๋ƒ์˜ ์ฐจ์ด. ์ƒํ™ฉ์— ๋”ฐ๋ผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

using System;
using System.Collections;

class Program {

    public IEnumerator Coroutine() {
        int i = 0;
        Console.WriteLine($"Coroutine {++i}");
        yield return null;

        Console.WriteLine($"Coroutine {++i}");
        yield return null;

        Console.WriteLine($"Coroutine {++i}");
        yield return null;
    }
    
    static void Main(string[] args) {
        Program program = new Program();
        IEnumerator coroutine = program.Coroutine();

        Console.WriteLine("Main 1");
        coroutine.MoveNext();
        Console.WriteLine("Main 2");
        coroutine.MoveNext();
        Console.WriteLine("Main 3");
        coroutine.MoveNext();
    }
}

// OUTPUT :
// Main 1
// Coroutine 1
// Main 2
// Coroutine 2
// Main 3
// Coroutine 3

์ถœ์ฒ˜: https://kukuta.tistory.com/371

 

 

728x90