赞
踩
Unity 中的 Task 和 C# 中的 Task 不同。
unity Task 属于 netstandard.dll
C# Task 属于 mscorlib.dll
不同之处:
Unity 主线程调用 async 方法时,不论是 await 之前还是之后,代码都在主线程运行
c# 主线程调用async 方法时,await之前由主线程运行,await之后由子线程运行
unity
async void task(){
语句1 //主线程调用
await taskMethod; //这里肯定是新线程执行了
语句2 //主线程调用
}
unity 这个改动的好处是
unity 中使用 async 来处理异步方法就不需要考虑线程安全问题了,可以代替协程。
相比于协程,Task 更加灵活,不需要 Monobehavior 来开启,可以进行错误捕获。
要注意的地方:
第一:
在主线程使用 task.wait 方法 或者 使用 task.Result 会导致死锁
看个例子:
上面的代码运行Unity 后 Unity 会卡死。原因是产生了死锁!
分析下原因。
taskValue.wait 会去等待task001 任务的执行完成。
await task() 运行完成之后, 上下文切换到主线程。
也就是说 Debug.Log(“task001 end!”); 这个是需要主线程来执行的, 然而主线现在正在忙着执行taskValue.Wait(),没有空执行 Debug.Log(“task001 end!”); 这就导致了 task001 在等主线程来执行, 主线忙着等待 task001()。导致主线程无法向下执行。
第二: 值类型在await 值类型的方法中,代码获得的是值类型的一个拷贝。
例子:
public struct taskTest { public int x; public async Task task() { x = 100; Debug.Log("Task " + Thread.CurrentThread.ManagedThreadId); await task01(); Debug.Log("Task01:" + Thread.CurrentThread.ManagedThreadId + "," + x); } public Task task01() { return Task.Factory.StartNew( () => Thread.Sleep(5000) ); } } monobehavior 中 void Start() { task(); } async Task task() { var tt = new taskTest(); await tt.task(); Debug.Log("xx:" + tt.x); }
可以发现子线程执行的 taskTest.task 方法中的实例 与 主线程中的 taskTest 实例不是同一个, taskTest.task 获得的是一个新副本。 具体原因就要看Unity源代码了。
参考
https://zhuanlan.zhihu.com/p/86168785
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。