美文网首页Unity
unity使用多线程

unity使用多线程

作者: _Bob_ | 来源:发表于2017-12-18 18:24 被阅读141次

        首先Unity一般是避免使用多线程的,unity提供了一种协程的概念(coroutine) yield,但是这个协程归根到底也不是多线程,它只是起到一个延迟执行的效果。

        但是为什么我们需要使用多线程呢?前段时间项目中有一些地方使用协程并不能达到很好的效果,比如在游戏内进行大批量的拷贝和移动文件时,UI显示上会出现卡死现象,我怀疑是主线程被阻塞了。换成多线程后成功解决了问题。

    适合使用多线程的地方

    ·解压缩资源

    ·IO操作

    ·网络请求

    ·大量的数据操作

    ·一些资源的加载

    使用多线程是请注意

    ·Unity API 无法在Thread中被调用,同时包括所有component

    · 变量都是共享的(都能指向相同的内存地址)

    · UnityEngine 定义的基本结构(int, float, struct 定义的数据类型)可以在分线程计算,如 Vector3(struct)可以, 但 Texture2d(class,根父类为 Object) 不可以

    如何使用多线程

        多线程使用时必须非常谨慎,而unity自带的Thread,并不是mono而是.net,是两套框架。therad的使用晦涩复杂,同时还需要注意线程安全问题。

        所以我选择了一个市面上封装比较好的Loom工具类,代码很少,将会在最后贴出来,非常好用。

    //RunAsync 用线程池,运行在子线程。

    public static Thread RunAsync(Action a)

    //主线程

    public static void QueueOnMainThread(Action action)

    public static void QueueOnMainThread(Action action, float time)

    举个栗子

    Loom.RunAsync(delegate {

    do something

    });

    全部代码

    using UnityEngine;

    using System.Collections;

    using System.Collections.Generic;

    using System;

    using System.Threading;

    using System.Linq;

    public class Loom : MonoBehaviour

    {

        public static int maxThreads = 10;

        public static int numThreads;

        private static Loom _current;

        private int _count;

        public static Loom Current

        {

            get

            {

                Initialize();

                return _current;

            }

        }

        void Awake()

        {

            _current = this;

            initialized = true;

        }

        public static bool initialized;

        static void Initialize()

        {

            if (!initialized)

            {

    if (!Application.isPlaying) {

    return;

    }

                initialized = true;

                var g = new GameObject("Loom");

                _current = g.AddComponent<Loom>();

            }

        }

        private List<Action> _actions = new List<Action>();

        public struct DelayedQueueItem

        {

            public float time;

            public Action action;

        }

        private List<DelayedQueueItem> _delayed = new List<DelayedQueueItem>();

        List<DelayedQueueItem> _currentDelayed = new List<DelayedQueueItem>();

        public static void QueueOnMainThread(Action action)

        {

            QueueOnMainThread(action, 0f);

        }

        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 Thread RunAsync(Action a)

        {

            Initialize();

            while (numThreads >= maxThreads)

            {

                Thread.Sleep(1);

            }

            Interlocked.Increment(ref numThreads);

            ThreadPool.QueueUserWorkItem(RunAction, a);

            return null;

        }

        private static void RunAction(object action)

        {

            try

            {

                ((Action)action)();

            }

            catch

            {

            }

            finally

            {

                Interlocked.Decrement(ref numThreads);

            }

        }

        void OnDisable()

        {

            if (_current == this)

            {

                _current = null;

            }

        }

        // Use this for initialization

        void Start() {

        }

        List<Action> _currentActions = new List<Action>();

        // Update is called once per frame

        void Update() {

            lock (_actions) {

                _currentActions.Clear();

                _currentActions.AddRange(_actions);

                _actions.Clear();

            }

            foreach (var a in _currentActions) {

                a();

            }

            lock (_delayed) {

                _currentDelayed.Clear();

                _currentDelayed.AddRange(_delayed.Where(d => d.time <= Time.time));

    foreach (var item in _currentDelayed) {

    _delayed.Remove(item);

    }

            }

            foreach (var delayed in _currentDelayed) {

                delayed.action();

            }

        }

    }

    相关文章

      网友评论

        本文标题:unity使用多线程

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