深入探讨Unity协程及其使用

文章讨论了Unity中的协程机制,其本质是C#的迭代器,用于异步操作。协程并非并发执行,可能导致的问题包括多个协程同时运行引起的逻辑错误。作者建议在使用协程时遵循“FIREANDFORGET”原则,避免无限循环协程,并指出在需要并发处理时应考虑多线程。文章还提出,状态机可能是比协程更优雅的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

深入探讨Unity协程及其使用

协程

协程在Unity中是个很重要的东东,相信很多人都使用过,它能够非常方便的进行异步等待操作,可以说,用好协程,可以使你的代码更加优雅,然而,如果用不好,代码就会有变成翔的可能,甚至已经变成了翔,你自己居然还不知道。那么,我们就来好好聊聊协程吧。

协程的本质

协程并不是Unity创造的,它本来就存在于C#。协程的本质是迭代器,通过调用MoveNext(),直到迭代结束。
通过下面的代码,可以清晰的看到他的工作原理:

static IEnumerator<int> MyCoroutine()
{
	yield return 0;
	yield return 1;
	for( int i = 2; i < 10; ++ i )
		yield return i;
}

static void Main(string[] args)
{
	var mc = MyCoroutine();
	while( mc.MoveNext())
	{
		Console.WriteLine( mc.Current );
	}
	Console.ReadKey();
}

在Unity的游戏循环中,每次循环或者说每帧都会去调用MoveNext(),于是看起来,协程“并行”了。然而,协程并不是线程,它本质并不是并发的。

协程带来的问题

请看下面的例子:
public float speed = 0.5f / 1f;
CanvasGroup group;

private void Start()
{
	group = GetComponenet<CanvasGroup>();
}

public void Show()
{
	StartCoroutine(_show());
}

public void Hide()
{
	StartCoroutine(_hide());
}

private IEnumerator _show()
{
	while( group.Alpha < 0.999 )
		group.Alpha += speed * Time.deltaTime;
	group.Alpha = 1;
}

private IEnumerator _hide()
{
	while( group.Alpha > 0.001 )
		group.Alpha -= speed * Time.deltaTime;
	group.Alpha = 0;
}

上面的例子中,实现了一个UI的渐隐和渐现功能,一般情况下,它能很好的工作。当你调用了Show(),他会渐现,当你调用了Hide(),他会渐隐。然而,它潜在的问题是,如果你调用了Show(),渐现到一半时(_show协程未结束),接着调用Hide(),那么两个协程将同时运行,一个负责增加group.Alpha,另一个负责减少group.Alpha,导致group.Alpha始终不会高于0.999,也始终不会低于0.001,界面就卡在那里了。
那么为了保证每次只有一个协程在运行,你可能会这么改:

public void Show()
{
	StopAllCoroutine();
	StartCoroutine(_show());
}

public void Hide()
{
	StopAllCoroutine();
	StartCoroutine(_hide());
}

虽然通过加一个StopAllCoroutine()能解决上面的问题,但最起码,它已经不怎么“优雅”了。更优雅的实现同样功能,应该考虑使用状态机,而不是协程。

再来看一个例子:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这是unity官方在B站发布的视频,他的大意是:第一,协程是语法糖,他本质上是一个状态机,加上一堆goto语句。第二,也是最重要的,不要让一个协程永远不退出,就是不要有上图例子中的while(true)这样的协程,他强烈不建议这么用,因为这样可能会有内存问题。有兴趣的可以去看看原视频——“豆知识 匿名类”。

到底应该什么时候用协程

使用协程应该满足“FIRE AND FORGET”原则,即“点火后忘记”原则。就是说,只需要发起它,而不用管它后续的情况(不需要时刻记得它),就可以使用协程。比如说,发起一个资源下载,然后等他出来结果。

另外,协程只工作在主线程,他只是循环的被调用,本身并不能解决并发的问题,所以,如果你想要并发,请使用多线程。

白猫,黑猫,抓到老鼠就是好猫,总之,没有绝对的好于坏,具体需求要具体分析,协程也好,线程也罢,各有各的优缺点,只要能实现功能需求,达到性能要求,就是好的,但这就需要我们深入的去理解功能点,分析需求逻辑。

协程Unity中是一种非常重要的多任务处理方式,它能够方便地进行异步等待操作,使代码更加优雅。在Unity中,协程实际上是一种函数,可以被中断和恢复执行。当协程执行到yield return语句时,它会暂停执行并将控制权交给协程管理器,让其他协程或主线程有机会执行。当等待的条件满足后,协程管理器会恢复执行该协程。 下面是一个简单的Unity协程使用示例,用于实现一个计时器程序: ```csharp public IEnumerator StartTime() { while (second > 0) { yield return new WaitForSeconds(1); second--; changeText(); Debug.Log(second); } if (second == 0) { button_xuzi.interactable = true; } } ``` 在这个示例中,`StartTime`是一个协程函数,通过使用`yield return new WaitForSeconds(1)`来实现每隔1秒执行一次循环体内的代码。当`second`大于0时,循环继续执行,否则计时器停止并激活一个按钮。 需要注意的是,协程使用时应避免让一个协程永远不退出,例如使用`while(true)`这样的循环。这样的用法可能会导致内存问题,因此不建议这样使用协程。\[3\] 希望这个示例能帮助你理解Unity协程使用。 #### 引用[.reference_title] - *1* *3* [深入探讨Unity协程及其使用](https://blog.youkuaiyun.com/sdhexu/article/details/129145654)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Unity协程的简单应用](https://blog.youkuaiyun.com/qq_45498613/article/details/129269894)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

示申○言舌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值