目录
区分进程(Process)、线程(Thread)和协程(Coroutine)
4.线程(Thread)、进程(Process)和协程(Coroutine)核心区别对比
在Unity和C#开发中,线程(Thread)、进程(Process)和协程(Coroutine)是处理多任务的核心概念,但它们的底层机制、适用场景和使用限制有本质区别。
区分进程(Process)、线程(Thread)和协程(Coroutine)
1.进程(Process):程序的独立运行实例
1.1.定义
进程是操作系统分配资源的基本单位,是一个程序(如Unity编辑器、编译后的游戏.exe)的独立运行实例。每个进程拥有自己独立的内存空间、文件句柄、网络端口等系统资源,与其他进程完全隔离。
1.2.核心特点
(1)独立性:进程间互不干扰,一个进程崩溃不会影响其他进程(例如Unity编辑器崩溃不会导致浏览器关闭)。
(2)资源隔离:进程间无法直接访问对方的内存,必须通过“进程间通信(IPC)”机制(如管道、Socket、共享内存)交换数据。
(3)开销大:创建/销毁进程需要操作系统分配/释放大量资源,速度较慢。
1.3.在Unity中的体现
运行Unity游戏时,整个游戏就是一个独立进程(在任务管理器中能看到Unity.exe或游戏名称的进程)。Unity编辑器本身也是一个进程,当点击“Play”按钮时,会启动一个“游戏运行进程”,与编辑器进程并行。
2.线程(Thread):进程内的执行单元
2.1.定义
线程是进程内的最小执行单元,一个进程可以包含多个线程,所有线程共享该进程的内存空间和资源(如变量、文件句柄)。线程是操作系统调度的基本单位(CPU直接执行线程)。
2.2.核心特点
(1)资源共享:同一进程内的线程共享内存,可直接访问全局变量、类实例等(但需注意线程安全)。
(2)轻量级:创建/销毁线程的开销远小于进程(无需分配独立内存空间)。
(3)抢占式调度:由操作系统调度,线程间通过“时间片轮转”或“优先级”抢占CPU执行权(开发者无法精确控制执行顺序)。
2.3.在Unity中的使用限制
(1)主线程:Unity游戏进程中,有一个特殊的“主线程”,负责执行Update、Start、渲染画面、处理用户输入等核心逻辑,所有UnityAPI(如transform.position、Instantiate)必须在主线程调用。
(2)工作线程:可通过System.Threading.Thread创建子线程(工作线程),但禁止在子线程中调用任何UnityAPI(会导致崩溃或异常),只能处理纯数据逻辑(如计算、文件读写、网络请求)。
(3)线程安全:多线程共享数据时,需用lock、Monitor等同步机制避免“数据竞争”。
2.4.适用场景
①CPU密集型任务:如大规模数据计算、图像处理(利用多核提升效率)。
②IO密集型任务:如读取大文件、下载网络资源(避免阻塞主线程)。
3.协程(Coroutine):单线程内的“协作式”任务
3.1.定义
协程是运行在单个线程内的“分步执行”函数,通过yieldreturn主动暂停执行,让出CPU给同一线程内的其他任务,待条件满足后再恢复执行。本质是“单线程内的逻辑拆分”,而非真正的并行。
3.2.核心特点
(1)单线程执行:协程始终运行在创建它的线程中(Unity中默认是主线程),不会创建新线程。
(2)协作式调度:通过yield return(如new WaitForSeconds(2)、null)主动暂停,开发者可精确控制暂停和恢复时机。
(3)轻量高效:创建协程几乎无开销(仅需维护函数执行上下文),可同时运行数千个协程。
3.3.使用
可直接调用UnityAPI(因为运行在主线程),适合与游戏生命周期交互的任务(如延迟、分帧加载)。
(1)IEnumerator接口:协程方法必须返回IEnumerator类型,提供了“迭代执行”的能力。
(2)yield return关键字:指定协程“暂停后,下一次从哪继续执行”。常见的yield return类型:
null或0:下一帧Update后继续执行。
new WaitForSeconds(时间):等待指定秒数后,下一帧Update后继续执行。
new WaitForFixedUpdate():等待到下一次FixedUpdate(物理更新帧)后执行。
new WaitForEndOfFrame():等待到当前帧所有渲染完成后执行。
WWW或UnityWebRequest:等待网络请求完成后执行(适合下载资源)。
(3)协程的启动
StartCoroutine(协程方法名()):直接调用协程方法。
StartCoroutine("协程方法名"):通过字符串指定协程方法名(需注意,这种方式停止时要对应使用字符串形式)。
(4)协程的停止
StopCoroutine("协程方法名"):停止“通过字符串启动”的协程。
StopAllCoroutines():停止当前脚本中所有正在运行的协程。
3.4.适用场景
①分帧加载:如“将10000条数据分10帧加载,避免单帧卡顿”。
②延迟操作:如“3秒后播放技能特效”。
③等待异步事件:如“等待资源加载完成后刷新UI”、“等待网络请求响应”
4.线程(Thread)、进程(Process)和协程(Coroutine)核心区别对比
| 对比维度 | 进程(Process) | 线程(Thread) | 协程(Coroutine) |
|---|---|---|---|
| 资源隔离 | 完全隔离(独立内存、句柄) | 共享进程资源(内存、句柄) | 共享所在线程的资源 |
| 创建开销 | 最大(需分配完整资源) | 中等(仅需栈空间和内核结构) | 最小(仅维护函数上下文) |
| 调度方式 | 操作系统调度,进程间完全独立 | 操作系统调度,抢占式(时间片/优先级) | 线程内自调度,协作式(yield主动让出) |
| 并行性 | 真正并行(多进程可在多核CPU同时运行) | 真正并行(多线程可在多核 CPU同时运行) | 模拟并行(单线程内切换执行,无真正并行) |
| Unity 限制 | 游戏本身是一个进程,与编辑器进程隔离 | 子线程禁止调用Unity API | 运行在主线程,可直接调用Unity API |
| 通信方式 | 需通过IPC(管道、Socket等) | 直接访问共享内存(需同步机制) | 直接访问同一线程内的变量(无需同步) |
| 典型用途 | 独立运行的程序(游戏、编辑器、浏览器) | 后台处理耗时任务(文件读写、计算) | 分步执行逻辑(延迟、分帧、等待事件) |
5.如何选择进程、线程、协程?
(1)进程:用于完全独立的程序(如Unity编辑器和游戏运行实例),极少在游戏逻辑中主动创建新进程。
(2)线程:用于处理“不涉及UnityAPI的耗时任务”(CPU密集型任务,如数据计算;IO密集型任务,如文件读写),需注意线程安全和主线程回调。
(3)协程:用于“需要与Unity交互的分步任务”(如分帧加载、延迟操作、等待异步事件),简单高效,无需处理线程同步。
在Unity开发中,最常用的是协程+主线程回调的子线程组合:用协程处理与游戏逻辑交互的分步任务,用子线程处理纯数据的耗时操作,完成后通过主线程调度器(如MainThreadDispatcher)更新UI或游戏对象。
好了,本次的分享到这里就结束啦,希望对你有所帮助~

863

被折叠的 条评论
为什么被折叠?



