
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading.Tasks; // Task
public class TaskExample : MonoBehaviour
{
    /* Task Method
     * Factory.StartNew(): 스레드를 생성과 동시에 시작
     * Start(): Task 스레드 시작
     * Wait(): Task 끝날 때까지 대기
     * **/
    void Start()
    {
        // 직접 호출, 스레드 생성 및 시작
        Task.Factory.StartNew( () => { Debug.Log( "Task" ); } );
        // Action
        Task task2 = new Task( new System.Action( DebugLog ) );
        task2.Start();
        // delegate 대리자 
        Task task3 = new Task( delegate { DebugLog(); } );
        task3.Start();
        // 람다식 
        Task task4 = new Task( () => DebugLog() );
        task4.Start();
        // 람다와 익명 메서드
        Task task5 = new Task( () => { DebugLog(); });
        task5.Start();
        // 각 Task가 끝날 때까지 대기
        // 대기하지 않으면 Main이 먼저 끝나서 결과를 보지 못함
        task2.Wait();
        task3.Wait();
        task4.Wait();
        task5.Wait();
    }
    void DebugLog()
    {
        Debug.Log("Task");
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading.Tasks; // Task
public class GenericTaskExample : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Task<int> intTask = Task.Factory.StartNew<int>( () => GetSize( "GenericTask " ) );
        /*
         * 메인 스레드에서 다른 작업 실행
         */
        int result = intTask.Result;
        Debug.Log( result );
    }
    int GetSize( string data )
    {
        return data.Length;
    }
}
위 경우는 Task에서 리턴값을 꼭 받아야 하는데
그 작업이 무거울 경우 /메인 스레드에서 다른 작업 실행/ 을 활용하여
메인 스레드에게 다른 일을 시키면 좋다고 한다. 
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
using System.Threading.Tasks;
public class CancellationTokenExample : MonoBehaviour
{
    // 1. 클래스 멤버로 CancellationTokenSource 선언
    CancellationTokenSource m_CancelTokenSource;
    Task<int> m_Task;
    
    void Start()
    {
        // 2. CancellationTokenSource 객체 생성
        m_CancelTokenSource = new CancellationTokenSource();
        CancellationToken cancellationToken = m_CancelTokenSource.Token;
        m_Task = Task.Factory.StartNew(TaskMethod, cancellationToken);
    }
    
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.C))
        {
            // CancellationTokenSource 의 Cancel() 를 통해 작업 취소
            m_CancelTokenSource.Cancel();
            if(m_Task != null)
            {
                Debug.Log( $"Count: {m_Task.Result}" );
            }
        }
    }
    private int TaskMethod()
    {
        int count = 0;
        for (int i = 0; i < 10; i++)
        {
            // 비동기 작업 메서드 안에서 작업이 취소되었는지 체크
            if (m_CancelTokenSource.Token.IsCancellationRequested)
            {
                break;
            }
            ++count;
            Thread.Sleep( 1000 );
        }
        return count;
    }
}using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
using System.Threading.Tasks;
public class AsyncAwaitExample : MonoBehaviour
{
    /* Async, Await Method
     * Run(): 비동기 시작
     * FromResult(): 비동기 시작 후 결과값을 얻음 */
    void Start()
    {
        TaskRun();
        TaskFromResult();
    }
    async void TaskRun()
    {
        var task = Task.Run( () => TaskRunMethod( 3 ) );
        int count = await task;
        Debug.Log( $"Count: {task.Result}" );
    }
    private int TaskRunMethod(int limit)
    {
        int count = 0;
        for (int i = 0; i < limit; i++)
        {
            ++count;
            Thread.Sleep( 1000 );
        }
        return count;
    }
    async void TaskFromResult()
    {
        int sum = await Task.FromResult( Add(1, 2) );
        Debug.Log( sum );
    }
    private int Add(int a, int b)
    {
        return a + b;
    }
}