WaitForSeconds 和 WaitForSecondsRealtime 一探究竟
一:相同点
等待xx时间后进行后续操作
二:不同点
- 受时间因子影响 WaitForSecondsRealtime 这个不会受到Time.Scale的影响,而WaitForSeconds会受到影响
- 记时方式不同
WaitForSeconds 对于同一个对象而言,无论多少次通过Corotuine调用都会同一时间结束,也就是并行的效果
WaitForSecondsRealtime 对于同一个对象而言,会以串行的方式结束时间等待。
举个例子:两个同时等待3s的操作,如果使用WaitForSeconds 那么两个请求都会在3s后结束;如果使用是WaitWaitForSecondsRealtime 那么将会在第6s进行结束
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour
{
void Start()
{
list1.Add("WaitForSeconds", new WaitForSeconds(3f));
list2.Add("WaitForSecondsRealtime", new WaitForSecondsRealtime(3f));
StartCoroutine(WaitSeconds("WaitForSeconds1"));
StartCoroutine(WaitSeconds("WaitForSeconds2"));
StartCoroutine(WaitRealSeconds("WaitRealSeconds1"));
StartCoroutine(WaitRealSeconds("WaitRealSeconds2"));
}
IEnumerator WaitSeconds(string key)
{
WaitForSeconds obj = list1["WaitForSeconds"];
Debug.Log(key + ">> begin:" + Time.time);
yield return obj;
Debug.Log(key + ">> end:" + Time.time);
}
IEnumerator WaitRealSeconds(string key)
{
WaitForSecondsRealtime obj = list2["WaitForSecondsRealtime"];
Debug.Log(key + ">> begin:" + Time.time);
yield return obj;
Debug.Log(key + ">> end:" + Time.time);
}
private void Update()
{
list2["WaitForSecondsRealtime"].Reset();
}
Dictionary<string, WaitForSeconds> list1 = new Dictionary<string, WaitForSeconds>();
Dictionary<string, WaitForSecondsRealtime> list2 = new Dictionary<string, WaitForSecondsRealtime>();
}
打印日志如下,两个红色的使用了WaitForSecondsRealTime会在第6s结束
三:探秘
WaitForSecondsRealtime 我们通过IL反编译是可以获取到源码的,通过源码我们可以看到每次进行下一次记时操作都是采用了(当前时间)Time.realtimeSinceStartup + (等待时间)waitTime作为延迟时间,所以也就不难理解两次等待的时间最后一次是6s了,内部其实是通过可一个叫KeepWaitting进行控制当有一个在进行等待的时候,第二个记时开始必须等到第一个记时结束。感兴趣的朋友可以去尝试着把这个变量进行修改,看会发生生么现象。
源码如下:
namespace UnityEngine
{
/// <summary>
/// <para>Suspends the coroutine execution for the given amount of seconds using unscaled time.</para>
/// </summary>
public class WaitForSecondsRealtime : CustomYieldInstruction
{
private float m_WaitUntilTime = -1f;
/// <summary>
/// <para>The given amount of seconds that the yield instruction will wait for.</para>
/// </summary>
public float waitTime
{
get;
set;
}
public override bool keepWaiting
{
get
{
bool flag = this.m_WaitUntilTime < 0f;
if (flag)
{
this.m_WaitUntilTime = Time.realtimeSinceStartup + this.waitTime;
}
bool flag2 = Time.realtimeSinceStartup < this.m_WaitUntilTime;
bool flag3 = !flag2;
if (flag3)
{
this.m_WaitUntilTime = -1f;
}
return flag2;
}
}
/// <summary>
/// <para>Creates a yield instruction to wait for a given number of seconds using unscaled time.</para>
/// </summary>
/// <param name="time"></param>
public WaitForSecondsRealtime(float time)
{
this.waitTime = time;
}
}
}
WaitForSeconds 的源码我们无从获得,底层通过了C++代码编写,所以只能猜测内部是使用了一个new的操作或者使用了几个类似集合的封装达到了同一个对象时间不受影响的效果,如果有能看到内部原理的朋友可以在这里给我留言。