加载中…
个人资料
彬彬寒灵
彬彬寒灵
  • 博客等级:
  • 博客积分:0
  • 博客访问:2,615
  • 关注人气:221
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

Unity中使用Loom主线程、子线程通信切换方法

(2018-11-14 12:13:19)
标签:

unity

loom

线程切换

通信

队列

分类: Unity
1.Loom原理

Loom继承自MonoBehaviour,在Unity生命周期管理中Update方法下检查需要回调的Action进行加锁并回调,确保在主线程执行,回调序列本身又作为静态数据保存,在任意线程调用添加,简单轻量

2.初始化优化

原版Loom的初始化方法较为繁琐,每个场景都需要进行初始化,其实可以使用Unity的永不销毁方法来将Loom作为一个永久物体保存下来。

因此,只需在游戏初始化场景的的主线程中调用如下方法一次即可:

Loom.Initialize(); 

然后在任意场景任意线程均可调用

Loom.QueueOnMainThread(()=>{ 
    //Todo
}); 
来完成主线程的操作

改进版Loom源码:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Threading;
using System.Linq;

///
/// Unity线程切换工具
///
public class Loom : MonoBehaviour
{
    public static int maxThreads = 8;
    static int numThreads;

    private static Loom _current;

    public static Loom Current
    {
        get
        {
            Initialize();
            return _current;
        }
   

    static bool initialized;

    ///
    /// 作为初始化方法自己调用,可在初始化场景调用一次即可
    ///
    public static void Initialize()
    {
        if (!initialized)
        {
            if (!Application.isPlaying)
                return;
            initialized = true;
            GameObject g = new GameObject("Loom");

            DontDestroyOnLoad(g);
            _current = g.AddComponent();
        }
    }

    private List _actions = new List();

    public struct DelayedQueueItem
    {
        public float time;
        public Action action;
    }

    private List _delayed = new List();

    List _currentDelayed = new List();

    public static void QueueOnMainThread(Action action)
    {
        QueueOnMainThread(action, 0f);
    }

    public static void QueueOnMainThread(Action action, float time)
    {
        if (time != 0)
        {
            if (Current != null)
            {
                lock (Current._delayed)
                {
                    Current._delayed.Add(new DelayedQueueItem {time = Time.time + time, action = action});
                }
            }
        }
        else
        {
            if (Current != null)
            {
                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 _currentActions = new List();

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


未改进版Loom源码

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 = 8;  
    static int numThreads;  

    private static Loom _current;  
    private int _count;  
    public static Loom Current  
    
        get  
        
            Initialize();  
            return _current;  
        
    

    void Awake()  
    
        _current = this;  
        initialized = true;  
    

    static bool initialized;  

    static void Initialize()  
    
        if (!initialized)  
        

            if(!Application.isPlaying)  
                return;  
            initialized = true;  
            var g = new GameObject("Loom");  
            _current = g.AddComponent();  
        

    

    private List _actions = new List();  
    public struct DelayedQueueItem  
    
        public float time;  
        public Action action;  
    
    private List _delayed = new  List();  

    List _currentDelayed = new List();  

    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 _currentActions = new List();  

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



    
}

地址:

参考资料:

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有