1、环境
- Unity 2021.3.21f1
2、结论
- Unity2021无法实现;
- Unity2022可以实现,新增的
AssetBundleUnloadOperation
,支持同步等待结束WaitForCompletion()
3、尝试强制阻塞主线程
既然Unity自己没提供阻塞的接口,我就想是否可以强制把主线程阻塞住,等子线程执行完成后再恢复? 把问题抛给GPT,得到了一个没了解过的工具类,可以完成这个任务,下面介绍下用法。
AutoResetEvent block = new AutoResetEvent(false);
asyncOperation.completed += (ao =>
{
block.Set(); // 异步操作完成后,恢复主线程
});
block.WaitOne(100000); // 阻塞当前(主)线程,超时时间10s
AutoResetEvent使用说明:
- 当对象处于非信号状态(non-signaled)时,调用
WaitOne()
会阻塞当前线程。
直到收到信号后,释放线程。- 构造方法参数
传true:对象默认处于信号(signaled)状态,第一次调用WaitOne()
便不会阻塞线程;
传false:对象默认处于非信号状态,第一次调用WaitOne()
会阻塞线程Set()
方法是给对象设置信号,如果有处于阻塞状态的对象,此时会释放线程- AutoResetEvent的对象,每次收到信号,释放阻塞线程后,都会把自己的状态重置,变成非信号状态,相当于自动调用了
Reset()
- 与
AutoResetEvent
相对应的,还有个ManualResetEvent
类。它俩的区别只在于上面一条说的特性,ManualResetEvent
不会再收到信号后,自动重置,需要手动调用Reset()
才会将对象变为非信号状态。
经测试,此路不通!!!
执行AsyncOperation asyncOperation = bundle.UnloadAsync(true);
之后,如果阻塞了主线程,则资源卸载的操作也不会执行了。无论是同一帧阻塞,还是下一帧阻塞,都是如此。
并且,阻塞恢复后,异步卸载的时长完全没减少。我测试的时候,执行卸载后,要经过4帧的时间asyncOperation.isDone
才会变为true。我把主线程阻塞10s后恢复,Unity还是要执行4帧时间isDone才会变为true。
为了排除主线程阻塞后,completed回调无法调回来的可能,我还尝试了死循环等待的方式:while(!asyncOperation.isDone) ;
,结论与上面相同。
网友评论