Unity零基础到进阶 | Unity中的多线程的使用,普通创建Thread + 使用Loom插件创建
【摘要】 前言在Unity中多线程其实并不常用,所以关于这块的知识也没有去研究的特别透彻所以本篇文章就来简单说一下多线程在Unity中的作用、限制以及用法 Unity中的多线程的使用Unity中除了主线程负责UI等绘制之外,还有协程、多线程可以使用。其中协程伴随着 主线程 ⼀起运⾏的⼀段程序,让程序在特定的时间内运行某些方法,协程是可以对Unity中的一些UI等属性进行方法调用的。但是多线程并不能直...
前言
- 在Unity中多线程其实并不常用,所以关于这块的知识也没有去研究的特别透彻
- 所以本篇文章就来简单说一下多线程在Unity中的作用、限制以及用法
Unity中的多线程的使用
Unity中除了主线程
负责UI等绘制之外,还有协程
、多线程
可以使用。
其中协程
伴随着 主线程 ⼀起运⾏的⼀段程序,让程序在特定的时间内运行某些方法,协程是可以对Unity中的一些UI等属性进行方法调用的。
但是多线程
并不能直接去处理Unity中的游戏对象,因为在Unity中,只能在主线程中去获取物体的组件、方法和游戏对象!
使用多线程的作用:
- 用线程加载配置下载资源,需要显示进度条
- 进行算法方面的数据处理
使用多线程可以调的内容:
- C#基本的变量
- 除了UnityEngine的API中的内容
- UnityEngined定义的一些基本结构也可以,比如Vector3(struct)可以调用,但是Texture2d(class,根目录为Object)就不可以。
方法一:普通方式创建多线程
在Unity中使用Thread
开辟一个子线程
然后在这个子线程中进行一些数据的计算、传值、与Android交互等业务处理。
但是并不能调用Unity中的一些API
示例如下:
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;
public class ThreadTest : MonoBehaviour
{
void Start()
{
//开辟一个子线程
Thread childThread1 = new Thread(CallToChildThread);
childThread1.Start();
}
//子线程负责处理的事情
public void CallToChildThread()
{
//调用主线程的内容
Debug.Log(test());
//打印结果:666
}
int test()
{
return 666;
}
}
方法二:使用Loom插件进行多线程的调用
常见的Unity使用多线程开发时,有一种是使用Loom插件
进行多线程的使用
Loom
是一个专门负责Unity中主线程与子线程交互的一个工具类,Loom插件
只有一个脚本,在Unity中导入使用即可
其中使用Loom开辟一个子线程方法
Loom.RunAsync(() =>
{
Thread childThread = new Thread(CallToChildThread);
childThread.Start();
});
使用Loom多线程调用Unity中的数据方法:
//使用Loom调用主线程的内容
Loom.QueueOnMainThread((param) =>
{
ThreadTxt.text = "子线程开启了";
}, null);
完整示例如下使用子线程调用主线程
的代码示例如下:
using System.Threading;
using UnityEngine;
using UnityEngine.UI;
public class ThreadTest : MonoBehaviour
{
public Text ThreadTxt;
void Start()
{
//使用Loom开辟一个子线程
Loom.RunAsync(() =>
{
Thread childThread = new Thread(CallToChildThread);
childThread.Start();
});
}
public void CallToChildThread()
{
//使用Loom调用主线程的内容
Loom.QueueOnMainThread((param) =>
{
ThreadTxt.text = "子线程开启了";
}, null);
}
}
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;
public static void Initialize()
{
if (!initialized)
{
if (!Application.isPlaying)
return;
initialized = true;
var g = new GameObject("Loom");
_current = g.AddComponent<Loom>();
#if !ARTIST_BUILD
UnityEngine.Object.DontDestroyOnLoad(g);
#endif
}
}
public struct NoDelayedQueueItem
{
public Action<object> action;
public object param;
}
private List<NoDelayedQueueItem> _actions = new List<NoDelayedQueueItem>();
public struct DelayedQueueItem
{
public float time;
public Action<object> action;
public object param;
}
private List<DelayedQueueItem> _delayed = new List<DelayedQueueItem>();
List<DelayedQueueItem> _currentDelayed = new List<DelayedQueueItem>();
public static void QueueOnMainThread(Action<object> taction, object tparam)
{
QueueOnMainThread(taction, tparam, 0f);
}
public static void QueueOnMainThread(Action<object> taction, object tparam, float time)
{
if (time != 0)
{
lock (Current._delayed)
{
Current._delayed.Add(new DelayedQueueItem { time = Time.time + time, action = taction, param = tparam });
}
}
else
{
lock (Current._actions)
{
Current._actions.Add(new NoDelayedQueueItem { action = taction, param = tparam });
}
}
}
public static Thread RunAsync(Action a)
{
Initialize();
while (numThreads >= maxThreads)
{
Thread.Sleep(100);
}
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<NoDelayedQueueItem> _currentActions = new List<NoDelayedQueueItem>();
// Update is called once per frame
void Update()
{
if (_actions.Count > 0)
{
lock (_actions)
{
_currentActions.Clear();
_currentActions.AddRange(_actions);
_actions.Clear();
}
for (int i = 0; i < _currentActions.Count; i++)
{
_currentActions[i].action(_currentActions[i].param);
}
}
if (_delayed.Count > 0)
{
lock (_delayed)
{
_currentDelayed.Clear();
_currentDelayed.AddRange(_delayed.Where(d => d.time <= Time.time));
for (int i = 0; i < _currentDelayed.Count; i++)
{
_delayed.Remove(_currentDelayed[i]);
}
}
for (int i = 0; i < _currentDelayed.Count; i++)
{
_currentDelayed[i].action(_currentDelayed[i].param);
}
}
}
}
总结
-
Unity中使用多线程有很多不方便的地方,一般来说有了协程的存在,也不会再去使用多线程
-
包括使用Loom插件其实也不是特别的方便
-
所以大家仁者见仁,遇到一些不是特别复杂的运算等情况使用协程就好啦!
-
协程的学习文章在这里,感兴趣的小伙伴可以来看看哦!
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)