Unity 异步与死锁

一、问题及疑问

先说事情起因:

public async Task<T> OpenWindow<T>(string assetName) where T : MonoBehaviour
{
	return await this.OpenWindow<T>(assetName, null);
}

项目用这个异步的方法来打开UI页面,之前用一直没有遇到问题。后来写了这么个方法来调用它:

private void OnBtnClick()
{
	Task<View> task = GameEntry.UI.OpenWindow<View>("CharacterPanel");
	_view = task.Result;
}

但其实这个方法在unity editor(2019.4版本)上跑也是没问题的,直到打了个win包做测试。发现一旦点击按钮调用这个方法,程序就会处于无响应阶段。后来,加了一行代码程序就能正常跑了:

private async void OnBtnClick()
{
	Task<View> task = GameEntry.UI.OpenWindow<View>("CharacterPanel");
    
    //添加了这一行
    await task;
            
	 _view = task.Result;
}

就感到比较疑惑,因为MSDN上是这么写的:
在这里插入图片描述
那也就是说在访问task.Result时,如果task还没执行完,那么调用线程是会在这里等待的。那为什么非要显式的加上 “await task;”

二、查阅资料

在stackoverflow上问了以后,想到可以从.Net和unity 的Task不同之处入手,后来查资料时发现了这篇文章(https://zhuanlan.zhihu.com/p/86168785),发现文章里的代码和我的很相似,所以初步确定我这里应该也是发生了死锁。死锁的原理在文章里已经说得很清楚了,就不重复了。
那接下来的问题就是 await和task.Result有什么区别,为什么使用await就不会产生死锁? What is the difference between await Task and Task.Result?这个问题下的高赞回答说的很简洁:task.Result 会阻塞当前线程来等待task结束(或者说是同步阻塞);而await 则是异步等待。所以await不会造成死锁。

那就又回到最开始的地方,为什么在unity editor模式下没有产生死锁?首先,测试了上面文章里的代码,的确会造成unity卡死,说明unity editor不具备自动打破死锁的能力。那也就是说原本的代码在unity中不会产生死锁而打成win包以后会发生死锁?所以应该继续去看unity和C#在task上的不同之处…

补:又看了些资料,发现这种先调用await task do something,然后直接访问task.Result是一个“标准”的死锁模型。但是在unity里就是没有卡住啊,摔!然后,unity的异步和C#相比并没有什么特殊的操作(也可能是我没查到),那唯一的解释就是unity editor模式下执行的比较快,在访问task.Result的时候,task已经执行完了,所以没有产生死锁。

放一篇MSDN的文档,顺便记几句话:异步和同步操作不要混用;异步方法async最好不要是void类型,因为void类型在try catch的时候会对抛出的异常进行包装,影响对异常的识别与定位。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值