美文网首页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