• UniRx框架


      之前一些简单功能用 Async await 的写法用的风生水起, 感觉还不错, 不过它的停止功能就比较尴尬, 一个 Task 没有办法去停止, 使用一个 CancelToken 的话还要自己去写里面的逻辑, 非常坑. 有个日本人写了一个整合到 Unity 的叫啥忘了.

      UniRx 其实很早就有人写了, 貌似也是个日本人, 参照的就是微软的 Reactive Extensions, 它也好在异步逻辑可以写成像同步的一样, 不停拼接起来就行了, 比如下面的例子 : 

        var parallel = Observable.WhenAll(
        ObservableWWW.Get("http://google.com/"),
        ObservableWWW.Get("http://bing.com/"),
        ObservableWWW.Get("http://unity3d.com/"));
    
        parallel.Subscribe(xs =>
        {
            Debug.Log(xs[0].Substring(0, 100)); // google
            Debug.Log(xs[1].Substring(0, 100)); // bing
            Debug.Log(xs[2].Substring(0, 100)); // unity
        });

      或者实际使用中的例子, 删掉主要代码后的 : 

        var clearStep = Observable.FromCoroutine(() => ClearIteratively(800));
        List<IObservable<Unit>> allSteps = new List<IObservable<Unit>>() { clearStep };
        foreach(var uploadData in m_points)
        {
            var download = Download(uploadData);
            allSteps.Add(download);
        }
    
        var _Rx = Observable.WhenAll(allSteps.ToArray()).SubscribeOn(Scheduler.ThreadPool).Do<Unit>((_) =>
        {
            // ...
        }).SubscribeOnMainThread().Do<Unit>((_) => { onReceived.Invoke(); }).SelectMany(() => ShowVisualisation(localDatas, Color.red, 100)).Subscribe();

      先做了一个协程的Clear, 然后进行多个数据的下载, 然后所有数据现在完成后在多线程中组装, 之后回到主线程通知, 然后进行协程的显示数据...

      然后最大的好处是我可以在任何时候进行停止逻辑 _Rx.Dispose(); 就行了, 它的执行点在协程的各个 yield 和每个拼接处, 随时都可以进行停止, 或是不再往下执行.

      唯一的问题是一旦进行 Subscribe() 之后, 就无法再在此流程上添加后续处理了, 有点尴尬...

      例子:

            var ob1 = ObservableWWW.Get("https://fanyi.baidu.com/");
    
            var ob2 = Observable.Timer(new System.TimeSpan(0, 0, 5));
    
            var ob3 = ObservableWWW.Get("https://www.baidu.com/");
    
            ob1.Do<string>(x => Debug.Log(x)).ContinueWith(ob2).ContinueWith(ob3).Do<string>(x => Debug.Log(x)).Subscribe();

      如果我是已经开始的一段逻辑:

            var disposable = ob1.Do<string>(x => Debug.Log(x)).ContinueWith(ob2).ContinueWith(ob3).Subscribe();
            // disposable ......

      这时候想要打印 ob3 的内容就没办法了.......

      虽然不完美不过对于异步流水线化的过程来说使用非常方便

    =========== 分割线 ============

      发现这人写的线程转换部分有问题, 不能正确转换线程!!!

        var ob1 = ObservableWWW.Get("https://fanyi.baidu.com/");
        var ob3 = ObservableWWW.Get("https://www.baidu.com/");
        Debug.Log("1 : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
        // 主线程 -> 子线程 -> 主线程
        Observable.WhenAll(ob1, ob3).SubscribeOn(Scheduler.MainThread).Do((_) =>
        {
            Debug.LogError("2 : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
        }).SubscribeOn(Scheduler.ThreadPool).Do((_) =>
        {
            Debug.LogError("3 : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
        }).SubscribeOnMainThread().Do((_) =>
        {
            Debug.LogError("4 : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
        }).Subscribe();

      

       结果得到个这个, 如果在开始就使用线程, 后面就全是线程了, 转换没有用...

        Debug.Log("1 : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
        // 主线程 -> 子线程 -> 主线程
        Observable.Start(() =>
        {
            Debug.LogError("2 : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
        }, Scheduler.ThreadPool).Do((_) =>
        {
            Debug.LogError("3 : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
        }).SubscribeOnMainThread().Do((_) =>
        {
            Debug.LogError("4 : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
        }).Subscribe();

      没法用, 自己改起来工程量还挺大的

    ------------------- 再次分割 -----------------------

      看了源码, 原来不是这样用的, 需要调用的接口是 ObserveOn 接口, SubscribeOnMainThread 改为使用 ObserveOnMainThread 即可.......

       Subscrible 在执行链中是反向执行的, 并且在节点上就直接执行了, 比如上面的例子, 倒过来看的话就是先请求进入主线程, 然后再执行了 Observable.Start 进入了工作线程, 之后一直在工作线程里跑.

    ================= 还是分割 ===============

      发现还是不正常 : 

        Debug.Log("1 : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
        var ob3 = ObservableWWW.Get("https://www.baidu.com/");
        Observable.WhenAll(ob3).ObserveOn(UniRx.Scheduler.ThreadPool).Select((_) =>
        {
            Debug.Log("2 : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
            return 100;
        }).ObserveOn(UniRx.Scheduler.MainThreadEndOfFrame).Do((_) => { Debug.Log("3 : " + System.Threading.Thread.CurrentThread.ManagedThreadId); }).Subscribe();

      运行后LOG只会打印前两个, 后面的执行不到...

       可真是个神奇的东西, 代码懒得看了, 用的烦躁

  • 相关阅读:
    每天一道LeetCode--141.Linked List Cycle(链表环问题)
    每天一道LeetCode--119.Pascal's Triangle II(杨辉三角)
    每天一道LeetCode--118. Pascal's Triangle(杨辉三角)
    CF1277D Let's Play the Words?
    CF1281B Azamon Web Services
    CF1197D Yet Another Subarray Problem
    CF1237D Balanced Playlist
    CF1239A Ivan the Fool and the Probability Theory
    CF1223D Sequence Sorting
    CF1228D Complete Tripartite
  • 原文地址:https://www.cnblogs.com/tiancaiwrk/p/15638334.html
Copyright © 2020-2023  润新知