zoukankan      html  css  js  c++  java
  • unity 多线程

    对于客户端来说,好的用户体验,需要保持一个快速响应的用户界面。于是便要求:网络请求、io操作等 开销比较大的操作必须在后台线程进行,从而避免主线程的ui卡顿。(注:协程也是主线程的一部分,进行大量的io操作也会造成UI卡顿)

    在 WPF 中,DispatcherObject 只能通过与它关联的 Dispatcher 进行访问。 例如,后台线程不能更新与 UI 线程中的 Dispatcher 关联的 Button 内容。

    在unity4.X中,unity的api 是线程不安全的,只允许主线程进行访问。于是,如果在后台线程中想调用unity的api,就必须从后台线程跨回主线程,进行调用。

    然而,unity中并不能直接使用 .net中的 dispatcher,或者像android activity中的runOnUiThread 从后台线程 跨回主线程。 

    那么,unity 多线程中,主线程和后台线程之间通信要用什么方法去实现呢?

    1、通过共享数据:

    顺序图大致如下,主线程中用携程循环等待,或者在update中进行检测,直到后台线程完成,修改IsFinish=true,主线程再进行对应的逻辑操作。

     

    详见demo中的CZCoroutine文件夹。(注:CZCoroutine为开发群里好友给的一个自己封装协程管理器,并可支持多线程。)

    2、实现一个Loom的管理器,将后台线程中需要在主线程中处理的委托添加到 List<Action> _actions中,并在unity的update中进行处理:

        public class Loom : MonoBehaviour
        {
    
            private static Loom _current;
    
            public static Loom Current
            {
                get
                {
                    if (_current == null && Application.isPlaying)
                    {
    
                        var g = GameObject.Find("Loom");
                        if (g == null)
                        {
                            g = new GameObject("Loom");
                        }
    
                        _current = g.GetComponent<Loom>() ?? g.AddComponent<Loom>();
                    }
    
                    return _current;
                }
            }
    
            private void Awake()
            {
                if (_current != null && _current != this)
                {
                    Destroy(gameObject);
                }
                else
                {
                    _current = this;
                }
            }
    
            private List<Action> _actions = new List<Action>();
    
            public class DelayedQueueItem
            {
                public float time;
                public Action action;
                public string name;
            }
    
            private List<DelayedQueueItem> _delayed = new List<DelayedQueueItem>();
    
            public static void QueueOnMainThread(Action action, float time, string name)
            {
                lock (Current._delayed)
                {
                    if (Current._delayed.Any(d => d.name == name))
                        return;
                    QueueOnMainThread(action, time);
                }
            }
    
            public static void QueueOnMainThread(Action action, string name)
            {
                QueueOnMainThread(action, 0, name);
            }
    
            public static void QueueOnMainThread(Action action, float time)
            {
                if (time != 0)
                {
                    lock (Current._delayed)
                    {
                        Current._delayed.Add(new DelayedQueueItem { time = Time.time + time, action = action });
                    }
                }
                else
                {
                    lock (Current._actions)
                    {
                        Current._actions.Add(action);
                    }
                }
            }
    
            public static void QueueOnMainThread(Action action)
            {
                lock (Current._actions)
                {
                    Current._actions.Add(action);
                }
            }
    
            public static void RunAsync(Action a)
            {
                var t = new Thread(RunAction);
                t.Priority = System.Threading.ThreadPriority.Normal;
                t.Start(a);
            }
    
            private static void RunAction(object action)
            {
                ((Action)action)();
            }
    
    
            private List<Action> toBeRun = new List<Action>();
            private List<DelayedQueueItem> toBeDelayed = new List<DelayedQueueItem>();
    
            private void Update()
            {
                //Process the non-delayed actions
                lock (_actions)
                {
                    toBeRun.AddRange(_actions);
                    _actions.Clear();
                }
                foreach (var a in toBeRun)
                {
                    try
                    {
                        a();
                    }
                    catch (Exception e)
                    {
                        Debug.LogError("Queued Exception: " + e.ToString());
                    }
                }
                toBeRun.Clear();
                lock (_delayed)
                {
                    toBeDelayed.AddRange(_delayed);
                }
                foreach (var delayed in toBeDelayed.Where(d => d.time <= Time.time))
                {
                    lock (_delayed)
                    {
                        _delayed.Remove(delayed);
                    }
                    try
                    {
                        delayed.action();
                    }
                    catch (Exception e)
                    {
                        Debug.LogError("Delayed Exception:" + e.ToString());
                    }
                }
                toBeDelayed.Clear();
    
            }
        }
    View Code

    详见: http://dsqiu.iteye.com/blog/2028503

              http://answers.unity3d.com/questions/305882/how-do-i-invoke-functions-on-the-main-thread.html

    3、unity多线程插件 Loom

         https://www.assetstore.unity3d.com/en/#!/content/7285

         这个插件和上面分享的工具类同名,而现在也找不到上面工具类的出处,或许是同个作者,进行了优化,封装拿到unity商店吧。

     如果你对C# 中的Thread多线程还不熟悉,推荐  http://www.albahari.com/threading/  进行学习

  • 相关阅读:
    【Redis过期Key监听】
    【ElasticSearch】ES线上脏数据处理
    【MySQL】实现线上千万数据表添加字段操作以及缓存刷新
    【转】【堆外内存】堆内内存与堆外内存
    【Redis连接超时】记录线上RedisConnectionFailureException异常排查过程
    【ElasticSearch】ES 读数据,写数据与搜索数据的过程
    【ElasticSearch】shards,replica,index之间的关系
    tomorrow多线程启动
    request接口下载附件
    request接口上传附件
  • 原文地址:https://www.cnblogs.com/fatlin/p/4641934.html
Copyright © 2011-2022 走看看