文章目录

  • 前言
  • 一、unity真的不支持多线程吗?
    • 1.unity中使用多线程
    • 2.unity中多线程的停止
    • 3.unity中使用多线程的问题
  • 二、协同程序
    • 1.协程的使用
    • 2.协程的原理
  • 总结

前言

Unity中的协程,即协同程序,是一个很好用的工具,我们在很多时候都会用到,但协程究竟是怎样的机制?和线程是什么样的区别?下面让我们来一探究竟。


一、unity真的不支持多线程吗?

首先,unity中是支持多线程的。初学unity时看到有些地方说,unity中不支持多线程,就没怎么尝试过。之后进一步学习时才更多的了解了一些,下面通过几个例子来看一下unity中多线程的使用。

1.unity中使用多线程

首先在unity场景中创建一个空物体,创建一个新的C#脚本,在类中定义一个方法,循环打印1,再定义一个线程对象,在Start()生命周期函数中开启线程。

代码如下:

    Thread t;// Start is called before the first frame updatevoid Start(){t = new Thread(Test);t.Start();}void Test(){while (true){print(1);}}

将脚本挂载到场景上的空物体,运行,发现可以正常打印出1,也没有报错。

2.unity中多线程的停止

如果做到了这一步,接下来会发现,即使停止运行,程序仍在继续打印1。尝试将线程对象改为后台线程,重新运行:

代码如下:

t.IsBackground = true;

发现仍然不停打印。原因,其实UnityEditor本身就是这个软件程序中的一根线程,当我们在脚本中新开一个线程时,它是和UnityEditor同步执行的,所以我们停止了UnityEditor的运行并不会影响这个线程的执行。解决方案:在脚本的生命周期函数OnDestory()中停止线程,这样停止运行时会调用场景上对象的OnDestory()方法,就会停止其它线程。
代码如下:

    void OnDestroy(){t.Abort();}

3.unity中使用多线程的问题

下面我们再通过一个例子看一下,为什么有unity中不支持多线程的这种说法。还是上述脚本,我们改一下Test方法:

代码如下:

    Thread t;// Start is called before the first frame updatevoid Start(){t = new Thread(Test);t.Start();}void Test(){while (true){print(transform.position);}}

注意这里将打印结果改为了transform.position,运行,发现报了这样一个错误:

提示get_transform是Component类中的一个属性中的get方法,涉及到unity中的一些反射机制,这里不做过多描述,简单来说提示的意思就是我们要打印的transform.position只能在主线程中执行。实际上我们在脚本中新开的线程无法访问绝大部分unity中的对象,都会报这个错误,所以会有unity不支持多线程的这种说法,但实际上这种说法并不完全正确。
虽然新开的线程无法访问unity中的很多对象,但是我们可以将一些复杂的算法计算、网络连接等逻辑抛给一个新的线程去处理,将处理的数据放在公共内存模块中,在unity主线程就可以访问使用了,关于这种案例我们之后再讨论,前面说了很多关于多线程的问题,下面来讲一下unity对于以上问题机制给出的解决方案——协程。


二、协同程序

协同程序简称协程,多在资源、场景异步加载等逻辑时使用,它的使用效果和线程有些类似,都可以在不卡住主程序的情况下开启另一段逻辑的执行,但是它和线程有本质上的区别,协程的执行是在主线程下,而不是在另一个线程中,所以它可以访问unity中的所有对象,而不会出现上述使用线程中遇到的问题。

1.协程的使用

协程的基本使用:声明一个返回值为IEnumerator的方法,用然后用MonoBehaviour中的StartCoroutine()方法开启协程。

代码如下:

     void Start(){//开启协程返回一个协程对象Coroutine co = StartCoroutine(Test());//关闭协程StopCoroutine(co);}IEnumerator Test(){while (true){print(1);//要有一个yield修饰的返回值yield return new WaitForSeconds(1);}}

协程方法是每秒钟打印一次1,这里关于协程的返回值暂时不做过多介绍,之后可能在别的文章中具体说明,读者也可看一下unity官方的描述,下面着重讲一下协程原理。

2.协程的原理

协程本质上包括两部分:
1、协程方法
2、协程调度器

协程方法即返回值为IEnumerator接口类型或其子类的方法,本质上是一个迭代器方法,不了解C#迭代器的读者可以先补充一下这方面的知识。我们进入IEnumerator接口看一下:

    public interface IEnumerator{//表示方法当前执行到的返回值object Current { get; }//继续执行方法,返回表示是否执行完毕bool MoveNext();//重置方法的执行位置void Reset();}

我们不使用MonoBehaviour的StartCoroutine方法,来执行一个协程:

代码如下:

     void Start(){IEnumerator ie = Test();print(ie.MoveNext());print(ie.Current);print(ie.MoveNext());print(ie.Current);print(ie.MoveNext());print(ie.Current);print(ie.MoveNext());print(ie.Current);}IEnumerator Test(){print(1);yield return 1;print(2);yield return "哈哈";print(3);yield return 3.14;print(4);yield return gameObject;}

unity中的运行结果:

由此可见,所谓协同程序,就是一步步的执行迭代器对象中的MoveNext()方法,调用MoveNext()方法会执行下一个yield return之前的逻辑,并且根据MoveNext()的返回值判断是否全部执行完毕,而通过yield return返回Current成员对象,来判断下一次执行MoveNext()的时机。而这些工作,就是由协同程序的第二部分——协程调度器来实现的。这里的协程调度器是unity引擎实现的,理论上我们是可以自己去实现一个协程调度器的,大家感兴趣的话可以自己实现一个,能进一步加深对协程的理解。

总结

总之,协同程序的存在很大程度上弥补了unity中使用多线程出现的问题,但在原理上与线程有本质上的区别,我们在使用时也要依据情景,选择更适合的方式。另外,文章中并没有过多的阐述协程的使用,如果读者没有这部分的基础需要自己学习一下,之后可能会单独发一篇文章来详细描述协程的使用。

Unity线程与协程相关推荐

  1. Unity C#笔记 协程详解(转)

    目录 什么是协程 多线程 协程 协程的使用场景 协程使用示例 Invoke的缺陷 协程语法 开启协程 终止协程 挂起 协程的执行原理 什么是协程 在Unity中,协程(Coroutines)的形式是我 ...

  2. unity如何解决协程开启频繁导致的程序卡顿

    unity如何解决协程开启频繁导致的程序卡顿 一.协程 协程并不会在Unity中开辟新的线程来执行,其执行仍然发生在主线程中.当我们有较为耗时的操作时,可以将该操作分散到几帧或者几秒内完成,而不用在一 ...

  3. 进程 线程 协程_进程,线程,协程那些事

    无论我们写出怎样的程序,最后都是由操作系统来运行我们的程序,而操作系统如何管理我们的程序,我们程序的数据如何保存和计算,这些都是操作系统需要处理的事情,我们只要将写好的程序交给操作系统就好. 虽然操作 ...

  4. python 多线程和协程结合_一文讲透 “进程、线程、协程”

    本文从操作系统原理出发结合代码实践讲解了以下内容: 什么是进程,线程和协程? 它们之间的关系是什么? 为什么说Python中的多线程是伪多线程? 不同的应用场景该如何选择技术方案? ... 什么是进程 ...

  5. 进程、线程、协程、通信方式

    文章目录 进程 线程 协程 进程.线程.协程的区别 概念 进程.线程共同点 进程.线程不同点 线程.协程比较 通信方式之间的差异 进程通信 管道(pipe) 有名管道 (namedpipe) 信号量( ...

  6. 打开线程 | 进程 | 协程的大门

    不知从几何起,可能是大三那年的操作系统考试,也可能是刚经历完的秋招,这些概念总是迷迷糊糊,可能自己回答的和其他人的答复也差不多,并没有什么亮点,通常都会以:「我们换个题」的方式结束,有时候也挺尴尬的. ...

  7. 线程,协程对比和Python爬虫实战说明

    此文首发于我的个人博客:线程,协程对比和Python爬虫实战说明 - zhang0peter的个人博客 这篇文章写的是我对线程和协程的理解,有错误之处欢迎指出. 举一个餐馆的例子.我们把一个餐厅当做一 ...

  8. 什么是 “进程、线程、协程”?

    作者 | 头文件 责编 | 王晓曼 来源 | 程序员小灰(ID:chengxuyuanxiaohui) 本文从操作系统原理出发结合代码实践讲解了以下内容: 什么是进程,线程和协程? 它们之间的关系是什 ...

  9. Kotlin极简教程:第9章 轻量级线程:协程

    原文链接:https://github.com/EasyKotlin 在常用的并发模型中,多进程.多线程.分布式是最普遍的,不过近些年来逐渐有一些语言以first-class或者library的形式提 ...

最新文章

  1. UIActivityViewController使用
  2. 7-1 抓老鼠啊~亏了还是赚了? (20 分)
  3. 收藏 | 使用Pytorch从头实现Canny边缘检测
  4. tensorflow 遇到的细节问题
  5. Spring.Net配置多数据源
  6. oracle mysql数据库管理工具下载_Oracle数据库管理工具PC版-Oracle数据库管理工具下载v15.0.21.0(32/64)-IE浏览器中文网站...
  7. 黑苹果无线网卡选择intel还是博通?及其驱动方式详解
  8. rtt segger 低功耗模式_Segger RTT使用注意事项
  9. 普及ERP不靠低价风暴(转)
  10. 夜神模拟器-软件apk存放目录
  11. Java生成随机数字和字母组合10位数
  12. python根据excel生成报表_python生成Excel图表(通过xlsxwriter)
  13. 秒针计时器 html,js实现秒表计时器
  14. 一段神奇的代码-关于PHP字符变量奇怪现象的解释
  15. 非root用户执行程序---sudo的使用
  16. BNUZ程协技术部2020寒假任务简单版(后端)
  17. Spring学习第4篇:Spring 的依赖注入
  18. vi 跳到文件最后一行
  19. IBM通过云端让量子计算机变得唾手可得
  20. Synchro Arts的软件正式支持Apple Silicon(M1)

热门文章

  1. 人工智能小白日记 语音情感分析探索之2 CNN相关及实验
  2. 互联网经典SQL面试题及答案解析
  3. Scala+Hadoop+Spark开发
  4. Redis架构设计实现
  5. DSP TMS320F280049C——互补波形(一)
  6. javaScript用函数的方法判断素数:判断一个数是否是素数(代码)
  7. 2003计算机应用基础题答案,计算机应用基础(Windows_XP+Office_2003)课后题答案
  8. python数据拟合固定参数_固定某些参数的双峰高斯分布拟合
  9. 解决Qt5屏幕翻转问题
  10. 爬虫实战——求是网周刊文章爬取