一般情况下我们说unity不支持多线程,是因为我们只能在unity主线程内无限制的访问unity相关api。
但是我们也是可以用Thread写多线程,只是在这样的分线程中我们无法获取unity组件运行unity相关代码。这其实算c#多线程技术。
后来版本中推出c# job system突破该限制,利用c# job system 系统我们可以写出简单而安全的多线程代码,并且可以和unity引擎交互增强游戏性能。
多线程代码的好处:提高性能。
对于提高帧率和延长移动设备电池寿命有着重大意义。
什么是单线程?
单线程计算就是:一次输入一条指令,一次输出一条结果。加载和完成程序的时间完全取决于需要CPU干多少活儿。
什么是多线程?
而多线程编程则是利用CPU的多核心特性,在同一时间处理多个线程。指令不是一个接一个的执行,而是同时执行。
一般情况下,程序开始会创建一个默认线程称为主线程。在主线程中又可以创建多个新的线程称为分线程,这些分线程彼此并行运行,处理完任务之后返回结果给主线程同步。
如果同时有多个任务要执行,那么就可以使用多线程。然而在游戏开发中,通常会有许多小指令需要同时执行,如果为他们都创建线程的话,则会获得许多生命周期都很短的线程,这就很考验CPU和操作系统的处理能力。
为此我们可以采用线程池技术来优化此种情况,但是线程池的存在又使得同一时间存在多个激活的线程,如果线程数多于CPU核心数,又会导致线程之间争抢CPU资源反而频繁的进行上下文切换。所以又应该尽量避免。
什么是Job System(作业系统)?
Job system通过job而不是thread来管理多线程代码。
作业系统通过多个内核来管理一组工作线程,通常情况下每一个逻辑CPU只有一个工作线程,从而避免上下文切换。
作业系统把作业放进作业队列执行。在作业系统中工作线程从作业队列中取出作业并执行,作业系统管理依赖并确保作业以一定的顺序执行。
什么是Job(作业)?
作业是完成一个特定任务的工作单位,接收参数并操作数据,类似于方法调用。作业是可以自包含的,或者在运行之前依赖其他作业的完成的。
什么是Job dependencies(作业依赖)?
在复杂的系统中,比如为游戏开发的系统中,作业通常不太可能是自包含的,而是相互依赖的,比如A作业处理数据给B作业使用。这种情况下作业系统会确保A作业处理完数据之前,B作业是不能被执行的。
什么是c# Job System中的安全系统?
一开始我们就说了c#作业系统是安全的,那为什么它是安全的呢?原因在于其中的安全系统。
竞争条件:
在多线程编程的过程中不可避免地会出现竞争条件的风险的,当一个操作的输出依赖于另一个它控制之外的进程执行的时机的时候就会出现竞争条件。
竞争条件并不总是bug,它只是一个不确定行为的来源。当它引发一个bug之后我们是很难定位准确也很难重现,因为它是依赖于执行时机的,哪怕在调试也是不可能的,因为断点会影响到进程执行时间。
所以竞争条件是多线程编程中最大的挑战。
安全系统:
unity的c# job system检查了所有竞争条件出现的可能从而避免我们受到竞争条件引发的bug的影响,更简单的编写更安全的多线程代码。
例如:当主线程发送数据的引用给job时,并不能确认主线程在读取数据的同时job是否在写入数据,这就会发生竞争条件。
解决方案:c# job system发送数据的拷贝给每一个job而非引用,这样每一个job之间的数据是隔离的从而避免上诉竞争条件的发生。
这种c# job system发送数据拷贝的方式意味着job只能使用 blittable data types.(Blittable类型是Microsoft.NET框架中的数据类型,在内存中对于托管和非托管代码具有相同的表示。)这种数据类型在托管代码和本机代码之间传递的时候不需要转化。
c# job system可以使用memcpy复制blittable 类型,并在unity的托管部分和本机部分之间传输数据。在调度作业时使用memcpy将数据放入本机内存,并在执行作业时让托管端访问。
什么是NativeContainer(本机容器)?
安全系统使用了数据拷贝的方式,导致数据停留在job中,为了使job和主线程之间数据共享就用到了NativeContainer。
NativeContainer是一种托管值类型,它为本机内存提供了一个相对安全的c#包装器。它包含一个指向非托管分配的指针。当与unity c# job system一起使用时,NativeContainer允许作业访问与主线程共享的数据,而不是使用副本。
Unity附带一个名为NativeArray的NativeContainer。还可以使用NativeSlice操作NativeArray,从而获得从特定位置开始特定长度的NativeArray子集。
NativeArray
ps:安全系统内置在本机容器中。
静态数据的访问会绕过安全系统。
下一篇会继续介绍Unity C# Job System使用
欢迎扫码关注公众号,获得持续更新
本文分享自微信公众号 - 游戏人的开发分享(No_2SeeYou)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。