美文网首页unitycsharpC#
Unity3D中的多线程新体验-Timer

Unity3D中的多线程新体验-Timer

作者: 雨落随风 | 来源:发表于2018-12-23 05:55 被阅读10次

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

    异常&解决方案

    非主线程不能调用
    Loom 提供的解决方案 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<Timer> timers 各处上锁。
    4. 如果在非主线程中TimerDriver初始化会报错,新增 Timer.IntializeDriver(),提供手动初始化TimerDriver 的能力,在主线程初始化不会这样麻烦。

    测试代码

    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();
        }
    }
    
    
    

    动画演示


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

    扩展阅读

    1. [Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享] (https://dsqiu.iteye.com/blog/2028503)
    2. 重构后的 Timer -GitHub
    3. Unity技术博客 - 客户端断点续传 - 简书 (这个演示了多线程中更新UI较为麻烦的一面)

    他的麻烦在于:
    逻辑跳跃跨度大,progress 要从线程中公开出来并在MonoBehaviour类中处理,由于下载完成回调只能使用基本类型,导致一个简单的 Complete 后加载场景的功能 逻辑四处分散。
    使用 Timer 或者 Loom 将 OnComplete 回调埋进去,然后这个 回调就能 调用 Unity的API了,逻辑也就很容易做到不分散了(测试了下,死循环里面用Timer 会死,Loom不会,我的尴尬癌...)。

    相关文章

      网友评论

        本文标题:Unity3D中的多线程新体验-Timer

        本文链接:https://www.haomeiwen.com/subject/bvrgkqtx.html