Unity3D中的多线程新体验-Timer

前面些时候要研究串口通讯,于是就接触到了多线程,期间呢,笔者想当然的把在线程里面使用了Unity 的 Text。然后就报错,然后呢就遇见了 Loom,嗯,设计的很巧妙,蛮好吃的!
所以,我就把自家曾经写的 Timer,重构了下,于是就有了本文,下面进入正题:

异常&解决方案

Unity3D中的多线程新体验-Timer_第1张图片
非主线程不能调用

Unity3D中的多线程新体验-Timer_第2张图片
Loom 提供的解决方案
Unity3D中的多线程新体验-Timer_第3张图片
Timer 提供的解决方案

Loom的设计

就是把操作Unity组件的逻辑块使用 Action 包裹埋入到非主线程的上下文,但这个线程执行到这个位置就把这些个 Action 抛入MonoBehaviour的 Update中执行他 ,实现的效果如下:

  1. 更优的代码的可读性和逻辑连续性
  2. 更小范围的数据可见性(闭包优势)
  3. 实时与 Unity 组件交互(闭包优势)

Timer的设计

只因为多看了一眼,才发现 Timer 的 TimerDriver 理念 原来跟这个 Loom 是那么的相近:
都是利用委托Action 把逻辑块插入其他逻辑块的上下文,然后利用闭包的优势共享这个被插逻辑块上下文的局部变量。
然后其实呢,执行这个 Action 的是另一个继承了MonoBehaviour 的类,在Timer中 我谓之:TimerDirver。

小结

综上,这个Loom 带来的 Unity多线程 炫酷体验,只需要简单的重构,俺家的 Tiemr 也必定兼并你的特色功能,下面就是重构大体思路

重构 Timer

  1. 剔除Timer 中 UnityEgine 相关的API : Time.realtimeSinceStartup 、Time.time。
  2. 将上述剔除的 CurrentTime 实际驱动 放到 TimerDriver Update中。
  3. 为线程安全,对定时器链表 List timers 各处上锁。
  4. 如果在非主线程中TimerDriver初始化会报错,新增 Timer.IntializeDriver(),提供手动初始化TimerDriver 的能力,在主线程初始化不会这样麻烦。

应用场景1-简单的应用

using UnityEngine;
using System.Threading.Tasks;
using QFramework.TimeExtend;
using Timer = QFramework.TimeExtend.Timer;
using UnityEngine.UI;

public class TestForTimer : MonoBehaviour
{
    public Text text;
    private void Awake()
    {
        Timer.IntializeDriver(); //首次初始化不能放在非主线程内。
    }
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.R))
        {
            this.FunctionA();
        }
    }
    internal void FunctionA()
    {
        Task task = new Task(() =>
        {
            string _name = "CreateWithTimer ←";
            Timer.AddTimer(0).OnCompleted(() =>
            {
                text.text = _name;  //先演示异常
                new GameObject(_name);
            });
        });
        task.Start();
    }
}


动画演示

Unity3D中的多线程新体验-Timer_第4张图片

Tips:
先尝试在 Task 内直接更新 Text组件数据 ,失败!
再尝试 Timer 内运行,完美解决报错!

应用场景2 - Http下载

参考:Unity技术博客 - 客户端断点续传 -

using UnityEngine;
using Timer = QFramework.TimeExtend.Timer;
using System;
using System.IO;
using UnityEngine.UI;

public class TestDownload : MonoBehaviour
{
    public string url = "http://localhost:8083/bigFile";
    public string savePath = "";
    public Text finish;
    public Text update;

    HttpDownLoader DownLoader;
    void Awake()
    {
        savePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "TestDownLoad");
        Timer.IntializeDriver();
        Loom.Initialize();
        DownLoader = new HttpDownLoader();
        DownLoader.OnDownLoadCompleted.AddListener(() =>
        {
            this.finish.text = "下载完成!";
        });
        DownLoader.OnDownLoadUpdate.AddListener(v =>
        {
            this.update.text = string.Format("下载进度:{0} %", (v * 100).ToString("f2"));
        });
    }
    private void Start()
    {
        this.DownLoader.DownLoad(url, savePath);
    }
    private void OnDisable()
    {
        this.DownLoader.Close();
    }
}

动画演示


Unity3D中的多线程新体验-Timer_第5张图片
使用 Timer 埋入 Update 事件更新下载进度

Tips:
使用 Timer 或者 Loom 将 OnComplete 和OnUpdate 回调埋进去,实现事件驱动的进度刷新和下载完成提示,无需额外的判断。

扩展阅读

  1. Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
  2. 重构后的 Timer -GitHub
  3. Unity技术博客 - 客户端断点续传 -

Unity非主进程内访问Unity组件报错、怎么在其他进程直接操作Unity组件、Unity多线程
可以做为 Loom 插件的课外知识,但不保证这个Timer 能够合理的处理高并发,毕竟笔者是个菜鸡儿,尤其是多线程编程。

你可能感兴趣的:(Unity3D中的多线程新体验-Timer)