一个小例子

分别使用Coruntine、Task与Thread实现数字随着时间不断增加;

Task与Coroutine的运行逻辑

  1. 点击开始程序
  2. 主线程开启
  3. Unity的内容在主线程上运行
  4. Scene被创建
  5. Scene里的object运行StartCoroutine,Task等内容
  6. 关闭程序
  7. Scene被关闭、Unity的内容被关闭(包括Coroutine)
  8. Task的任务被关闭(由于找不到Object,报错,详见Task实现方法)
  9. 主线程关闭

Coroutine实现方法

先上代码:

void Start()
{
    _ = StartCoroutine(KeepAddValueCoroutine());
}
/// <summary>
/// 协程
/// </summary>
/// <returns></returns>
private IEnumerator KeepAddValueCoroutine()
{
    int value = 0;
    while (true)
    {
    coroutineText.text = "协程:" + (value++).ToString();
    yield return null;
    //yield return new WaitForSeconds(1);
    //yield return new WaitForFixedUpdate();
    //yield return new WaitForEndOfFrame();
    }
}

说明与注意事项:

  • Unity本身是单线程运行的
  • Coroutine的本质是Unity在主线程上模拟了多线程
  • 需要在迭代器中加入yield return让副线程能够跳出
  • 如上面的代码,可以使用多种跳出的条件
  • Coroutine是Untiy的实现方式

Task实现方式

先上代码:

    void Start()
    {
        _ = KeepAddValueTask();
        //KeepAddValueTaskVoid();
    }
    /// <summary>
    /// Task 会报错
    /// </summary>
    private async void KeepAddValueTaskVoid()
    {
        int value = 0;
        while (true)
        {
            taskText.text = "Task:" + (value++).ToString();
            await Task.Yield();
            //await Task.Delay(1000);
            taskText.text = "Test End";
        }
    }
    /// <summary>
    /// Task不会报错,需要自己TryCatch
    /// </summary>
    /// <returns></returns>
    private async Task KeepAddValueTask()
    {
        try
        {
            int value = 0;
            while (true)
            {
                taskText.text = "Task:" + (value++).ToString();
                await Task.Yield();
                //await Task.Delay(1000);
            }
        }
        catch (System.Exception e)
        {
            print(e);
            throw;
        }
    }

说明与注意事项:

  • Task是C#自带的多线程方法,需要引入命名空间“using System.Threading.Tasks;”
  • 可以使用async void xx()和async Task xx()两种实现方法
  • 区别在于返回值为Task的方法不会报错,需要自己进行TryCatch(参见代码)
  • Task所创建的进程独立于Unity,也就是说Unity停止运行后Task不一定会立刻停止,因此可能造成找不到GameObject的报错
  • 报错:UnityEngine.MissingReferenceException: The object of type 'Text' has been destroyed but you are still trying to access it.
    Your script should either check if it is null or you should not destroy the object.
  • 需要使用awit 来跳出该进程(类似于协程的yield retrun)
  • 也可以使用await Task.Delay(int,单位为毫秒)来延迟运行,实现计时器的效果。

Thread实现方法

先看代码:

    void Start()
    {
        thread = new Thread(KeepAddValueThread);
        thread.Start();
    }
    private void Update()
    {
        threadText.text = "Thread:" + ThreadValue.ToString();
    }
    private void KeepAddValueThread()
    {
        
        while (ThreadValue < int.MaxValue)
        {
            ThreadValue++;
            Thread.Sleep(1);
        }
    }

说明与注意事项:

  • 使用Thread需要先引入命名空间"using System.Threading;"
  • Thread是真正的多线程,与Task、Coroutine有本质区别
  • Thread内只能进行传值,不能传递Unity内的Object
  • 可以在Thread内修改的:int、float、string、bool、struct、Vector3、List、Dictionary等
  • 使用Thread.Sleep(int,单位为毫秒)来延迟运行,实现计时器的效果。

参考资料

【阿P的Unity备忘录】了解Coroutine、Task和Thread(一)

【阿P的Unity备忘录】进一步了解Coroutine(二)