异步
C# 异步
因为同步进程会出现阻塞的情况,为了避免卡顿,以及在处理数据时仍然可以接收用户新的访问,异步的思想就出现了
异步可以理解为,在调用异步函数的时候,函数会直接返回,然后剩下的部分等同于在一个新线程中运行
异步操作的关键字是asnyc
,await
,当一个方法具有 async
的签名时, 它会向编译器发出信号,说明此方法包含 await
语句;也包含异步操作。
windows官方定义:
异步操作后跟同步操作的这种组合是一个异步操作。 换言之,如果操作的任何部分是异步的,整个操作就是异步的。
Unity 异步
Unity还提供了一系列的异步操作,方便大家根据需要进行选择。这些异步操作包括Resources的加载、场景的加载、Asset Bundle的加载、NavMesh的生成等等。当然,这些异步操作的底层实现各不相同。有些是独立线程处理的,有些则是利用Unity内部的JobSystem,也有一些是二者结合使用的。
在Unity中使用协程搭配异步来写代码更佳,例如通过异步加载场景,在加载过程中通过每帧更新进度条给予玩家一个反馈,就可以在协程中调用异步加载场景的方法,然后暂停协程,等待当前一帧结束,然后更新进度条,反复之后,就完成进度条显示进度加载场景的效果。
这里有四点需要注意:
- 首先创建一个unity自定义
AsyncOperation
类的对象,来承接unity异步加载场景的返回值,这里的返回值就是刚才的那个AsyncOperation
类,作用是管理异步加载的进度,以及操控加载完毕后场景是否显示- 通过
yield return new WaitForEndOfFrame()
达到协程的一个暂停,不然很快进度条就跑过去了,可能这个时候场景数据还没有加载完- 异步加载场景函数调用一次就好,调用多次的话,出现bug先不说,如果所要加载的场景特别大的话,估计CPU就报废了(开个玩笑),所以在调用完异步之后,要做一个标记,循环再进来之后不进入异步的语句
- 因为加载场景,有可能在进度条还没有走完之前,场景就加载好了,所以要保证场景加载完毕之后场景不显示,需要用到
ao.allowSceneActivation = false;
语句,当然,在进度条加载完成之后,调用ao.allowSceneActivation = false;
语句显示所加载的场景
代码如下:
public class Loading : MonoBehaviour
{
public string sceneName;
private Text text_LoadProgress;
private AsyncOperation ao;
private bool isLoad = false;
private void Awake()
{
text_LoadProgress = GetComponent<Text>();
EventCenter.AddListener(EventDefine.startLoadScene, StartLoad);
gameObject.SetActive(false);
}
private void OnDestroy()
{
EventCenter.RemoveListener(EventDefine.startLoadScene, StartLoad);
}
private void StartLoad()
{
gameObject.SetActive(true);
StartCoroutine("Load");
}
public IEnumerator Load()
{
int displayProgress = -1;
int toProgress = 100;
while (displayProgress < toProgress)
{
++displayProgress;
ShowProgress(displayProgress);
if(!isLoad)
{
ao = SceneManager.LoadSceneAsync(sceneName);
ao.allowSceneActivation = false;
isLoad = true;
}
yield return new WaitForEndOfFrame();
}
if(displayProgress == 100)
{
ao.allowSceneActivation = true;
StopCoroutine("Load");
}
}
private void ShowProgress(int progress)
{
text_LoadProgress.text = progress.ToString() + "%";
}
}