热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享

原文地址:http:dsqiu.iteye.comblog2028503熟悉Unity的developer都知道在Unity中的线程不能使用Unity的对象,但可以使用Uni

原文地址http://dsqiu.iteye.com/blog/2028503

         熟悉Unity的developer都知道在Unity中的线程不能使用Unity的对象,但可以使用Unity的值类型变量,如Vector3等。这样就使得线程在Unity中显的很鸡肋和蹩脚,因为很多函数很都是UnityEngine类或函数的调用的,对于哪些是可以在多线程使用,风雨冲进行了如下总结:

 

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

1. 不是UnityEngine的API能在分线程运行

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

3. UnityEngine定义的基本类型的函数可以在分线程运行,如

       int i = 99;

       print (i.ToString());

       Vector3 x = new Vector3(0,0,9);

       x.Normalize();

类的函数不能在分线程运行

       obj.name 

实际是get_name函数,分线程报错误:get_name  can only be called from the main thread.

       Texture2D tt = new Texture2D(10,10);

实际会调用UnityEngine里的Internal_Create,分线程报错误:Internal_Create  can only be called from the main thread.

其他transform.position,Texture.Apply()等等都不能在分线程里运行。

 结论: 分线程可以做 基本类型的计算, 以及非Unity(包括.Net及SDK)的API。

        D.S.Qiu觉得Unity做了这个限制,主要是Unity的函数执行机制是帧序列调用,甚至连Unity的协程Coroutine的执行机制都是确定的,如果可以使用多线程访问UnityEngine的对象和api就得考虑同步问题了,也就是说Unity其实根本没有多线程的机制,协程只是达到一个延时或者是当指定条件满足是才继续执行的机制。

        我们的项目目前还有没有比较耗时的计算,所以还没有看到Thread的使用。本来一直没有太考虑着方面的事情,直到在UnityGems.com看到Loom这个类,叹为观止呀。直接贴出人家的介绍(没必要翻译了大笑):

Threads on a Loom

Our class is called Loom.  Loom lets you easily run code on another thread and have that other thread run code on the main game thread when it needs to.

There are only two functions to worry about:

  • RunAsync(Action) which runs a set of statements on another thread
  • QueueOnMainThread(Action, [optional] float time) - which runs a set of statements on the main thread (with an optional delay).

You access Loom using Loom.Current - it deals with creating an invisible game object to interact with the games main thread.

        

        我们只需要关系两个函数:RunAsync(Action)和QueueOnMainThread(Action, [optional] float time) 就可以轻松实现一个函数的两段代码在C#线程和Unity的主线程中交叉运行。原理也很简单:用线程池去运行RunAsync(Action)的函数,在Update中运行QueueOnMainThread(Acition, [optional] float time)传入的函数。

 

直接贴出源码,供拜读:

C#代码  收藏代码
  1. using UnityEngine;  
  2. using System.Collections;  
  3. using System.Collections.Generic;  
  4. using System;  
  5. using System.Threading;  
  6. using System.Linq;  
  7.   
  8. public class Loom : MonoBehaviour  
  9. {  
  10.     public static int maxThreads = 8;  
  11.     static int numThreads;  
  12.       
  13.     private static Loom _current;  
  14.     private int _count;  
  15.     public static Loom Current  
  16.     {  
  17.         get  
  18.         {  
  19.             Initialize();  
  20.             return _current;  
  21.         }  
  22.     }  
  23.       
  24.     void Awake()  
  25.     {  
  26.         _current = this;  
  27.         initialized = true;  
  28.     }  
  29.       
  30.     static bool initialized;  
  31.       
  32.     static void Initialize()  
  33.     {  
  34.         if (!initialized)  
  35.         {  
  36.           
  37.             if(!Application.isPlaying)  
  38.                 return;  
  39.             initialized = true;  
  40.             var g = new GameObject("Loom");  
  41.             _current = g.AddComponent();  
  42.         }  
  43.               
  44.     }  
  45.       
  46.     private List _actions = new List();  
  47.     public struct DelayedQueueItem  
  48.     {  
  49.         public float time;  
  50.         public Action action;  
  51.     }  
  52.     private List _delayed = new  List();  
  53.   
  54.     List _currentDelayed = new List();  
  55.       
  56.     public static void QueueOnMainThread(Action action)  
  57.     {  
  58.         QueueOnMainThread( action, 0f);  
  59.     }  
  60.     public static void QueueOnMainThread(Action action, float time)  
  61.     {  
  62.         if(time != 0)  
  63.         {  
  64.             lock(Current._delayed)  
  65.             {  
  66.                 Current._delayed.Add(new DelayedQueueItem { time = Time.time + time, action = action});  
  67.             }  
  68.         }  
  69.         else  
  70.         {  
  71.             lock (Current._actions)  
  72.             {  
  73.                 Current._actions.Add(action);  
  74.             }  
  75.         }  
  76.     }  
  77.       
  78.     public static Thread RunAsync(Action a)  
  79.     {  
  80.         Initialize();  
  81.         while(numThreads >= maxThreads)  
  82.         {  
  83.             Thread.Sleep(1);  
  84.         }  
  85.         Interlocked.Increment(ref numThreads);  
  86.         ThreadPool.QueueUserWorkItem(RunAction, a);  
  87.         return null;  
  88.     }  
  89.       
  90.     private static void RunAction(object action)  
  91.     {  
  92.         try  
  93.         {  
  94.             ((Action)action)();  
  95.         }  
  96.         catch  
  97.         {  
  98.         }  
  99.         finally  
  100.         {  
  101.             Interlocked.Decrement(ref numThreads);  
  102.         }  
  103.               
  104.     }  
  105.       
  106.       
  107.     void OnDisable()  
  108.     {  
  109.         if (_current == this)  
  110.         {  
  111.               
  112.             _current = null;  
  113.         }  
  114.     }  
  115.       
  116.       
  117.   
  118.     // Use this for initialization  
  119.     void Start()  
  120.     {  
  121.       
  122.     }  
  123.       
  124.     List _currentActions = new List();  
  125.       
  126.     // Update is called once per frame  
  127.     void Update()  
  128.     {  
  129.         lock (_actions)  
  130.         {  
  131.             _currentActions.Clear();  
  132.             _currentActions.AddRange(_actions);  
  133.             _actions.Clear();  
  134.         }  
  135.         foreach(var a in _currentActions)  
  136.         {  
  137.             a();  
  138.         }  
  139.         lock(_delayed)  
  140.         {  
  141.             _currentDelayed.Clear();  
  142.             _currentDelayed.AddRange(_delayed.Where(d=>d.time <= Time.time));  
  143.             foreach(var item in _currentDelayed)  
  144.                 _delayed.Remove(item);  
  145.         }  
  146.         foreach(var delayed in _currentDelayed)  
  147.         {  
  148.             delayed.action();  
  149.         }  
  150.           
  151.           
  152.           
  153.     }  
  154. }  

 

 

       怎么实现一个函数内使用多线程计算又保持函数体内代码的顺序执行,印象中使用多线程就是要摆脱代码块的顺序执行,但这里是把原本一个函数分拆成为两部分:一部分在C#线程中使用,另一部还是得在Unity的MainThread中使用,怎么解决呢,还得看例子:

 

C#代码  收藏代码
  1. //Scale a mesh on a second thread  
  2. void ScaleMesh(Mesh mesh, float scale)  
  3. {  
  4.     //Get the vertices of a mesh  
  5.     var vertices = mesh.vertices;  
  6.     //Run the action on a new thread  
  7.     Loom.RunAsync(()=>{  
  8.         //Loop through the vertices  
  9.         for(var i = 0; i < vertices.Length; i++)  
  10.         {  
  11.             //Scale the vertex  
  12.             vertices[i] = vertices[i] * scale;  
  13.         }  
  14.         //Run some code on the main thread  
  15.         //to update the mesh  
  16.         Loom.QueueOnMainThread(()=>{  
  17.             //Set the vertices  
  18.             mesh.vertices = vertices;  
  19.             //Recalculate the bounds  
  20.             mesh.RecalculateBounds();  
  21.         });  
  22.    
  23.     });  
  24. }  

        这个例子是对Mesh的顶点进行放缩,同时也是一个使用闭包(closure)和lambda表达式的一个很好例子。看完例子,是不是很有把项目中一些耗时的函数给拆分出来,D.S.Qiu就想用这个方法来改进下NGUI的底层机制(看下性能不能改进)。

 

 

 

小结:

       D.S.Qiu在编程技术掌握还是一个菜鸟,Thread还是停留在实现Runable接口或继承Thread的一个水平上,对多线程编程的认识还只是九牛一毛。本来我以为Loom的实现会比较复杂,当我发现只有100多行的代码是大为惊叹,这也得益于现在语言的改进,至少从语言使用的便利性上还是有很大的进步的。

       有了Loom这个工具类,在很多涉及UnityEngine对象的耗时计算还是可以得到一个解决方法的:

               如在场景中用A*算法进行大量的数据计算

               变形网格中操作大量的顶点
               持续的要运行上传数据到服务器
               二维码识别等图像处理

        Loom简单而又巧妙,佩服Loom的作者。

 

        如果您对D.S.Qiu有任何建议或意见可以在文章后面评论,或者发邮件(gd.s.qiu@gmail.com)交流,您的鼓励和支持是我前进的动力,希望能有更多更好的分享。



推荐阅读
  • 本指南介绍了如何在ASP.NET Web应用程序中利用C#和JavaScript实现基于指纹识别的登录系统。通过集成指纹识别技术,用户无需输入传统的登录ID即可完成身份验证,从而提升用户体验和安全性。我们将详细探讨如何配置和部署这一功能,确保系统的稳定性和可靠性。 ... [详细]
  • 在多线程并发环境中,普通变量的操作往往是线程不安全的。本文通过一个简单的例子,展示了如何使用 AtomicInteger 类及其核心的 CAS 无锁算法来保证线程安全。 ... [详细]
  • 在 Linux 环境下,多线程编程是实现高效并发处理的重要技术。本文通过具体的实战案例,详细分析了多线程编程的关键技术和常见问题。文章首先介绍了多线程的基本概念和创建方法,然后通过实例代码展示了如何使用 pthreads 库进行线程同步和通信。此外,还探讨了多线程程序中的性能优化技巧和调试方法,为开发者提供了宝贵的实践经验。 ... [详细]
  • 本文将介绍如何在混合开发(Hybrid)应用中实现Native与HTML5的交互,包括基本概念、学习目标以及具体的实现步骤。 ... [详细]
  • VB.net 进程通信中FindWindow、FindWindowEX、SendMessage函数的理解
    目录一、代码背景二、主要工具三、函数解析1、FindWindow:2、FindWindowEx:3、SendMessage: ... [详细]
  • 多线程基础概览
    本文探讨了多线程的起源及其在现代编程中的重要性。线程的引入是为了增强进程的稳定性,确保一个进程的崩溃不会影响其他进程。而进程的存在则是为了保障操作系统的稳定运行,防止单一应用程序的错误导致整个系统的崩溃。线程作为进程的逻辑单元,多个线程共享同一CPU,需要合理调度以避免资源竞争。 ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • 在尝试对 QQmlPropertyMap 类进行测试驱动开发时,发现其派生类中无法正常调用槽函数或 Q_INVOKABLE 方法。这可能是由于 QQmlPropertyMap 的内部实现机制导致的,需要进一步研究以找到解决方案。 ... [详细]
  • 使用 ListView 浏览安卓系统中的回收站文件 ... [详细]
  • 卓盟科技:动态资源加载技术的兼容性优化与升级 | Android 开发者案例分享
    随着游戏内容日益复杂,资源加载过程已不仅仅是简单的进度显示,而是连接玩家与开发者的桥梁。玩家对快速加载的需求越来越高,这意味着开发者需要不断优化和提升动态资源加载技术的兼容性和性能。卓盟科技通过一系列的技术创新,不仅提高了加载速度,还确保了不同设备和系统的兼容性,为用户提供更加流畅的游戏体验。 ... [详细]
  • 本文深入探讨了Java多线程环境下的同步机制及其应用,重点介绍了`synchronized`关键字的使用方法和原理。`synchronized`关键字主要用于确保多个线程在访问共享资源时的互斥性和原子性。通过具体示例,如在一个类中使用`synchronized`修饰方法,展示了如何实现线程安全的代码块。此外,文章还讨论了`ReentrantLock`等其他同步工具的优缺点,并提供了实际应用场景中的最佳实践。 ... [详细]
  • Hadoop的文件操作位于包org.apache.hadoop.fs里面,能够进行新建、删除、修改等操作。比较重要的几个类:(1)Configurati ... [详细]
  • 本文详细介绍了Java反射机制的基本概念、获取Class对象的方法、反射的主要功能及其在实际开发中的应用。通过具体示例,帮助读者更好地理解和使用Java反射。 ... [详细]
  • javax.mail.search.BodyTerm.matchPart()方法的使用及代码示例 ... [详细]
author-avatar
vbppn65853
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有