关于今天遇到的协程重复开启的问题

文章讨论了在Unity中,如何避免Coroutine重复开启导致的多个实例运行,强调了在重启协程前务必停止旧实例。作者提供了示例代码和测试,说明了协程控制的正确用法,包括指定唯一参数和使用StopCoroutine方法来管理协程生命周期。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述:

``Coroutine的重复开启;出现多个协程实例同时运行:如果在重新启动协程之前没有停止之前的协程实例,可能会导致多个协程实例同时运行,进一步加剧速度累加的问题。

解决方式:

``在重新启动协程之前,先停止之前的协程实例,确保只有一个协程在运行。

	public void Start()
	{
		SwitchButton.onClick.AddListener(
            Model.IsRunning = !Model.IsRunning;
            if (Model.IsRunning)
            {
                TurnOnMarquee();
            }
            else
            {
                TurnOffMarquee();
            });//绑定了跑马灯的控制开关;调用后台的判断条件,判定是否开启;
	}
//一开始我是这样写的:
    public void TurnOffMarquee()
    {
        StopCoroutine(MarqueeRunning());//每次点击开关都会关闭一个协程实例;
    }

    public void TurnOnMarquee()
    {
        StartCoroutine(MarqueeRunning());//每次点击开关,都会重新创建一个协程实例;
    }//这里要注意这两个协程实例可能并不一样;

//我写的协程函数;主要是想写一个跑马灯,用协程循环跑动;
    IEnumerator MarqueeRunning()
    {
        DisplayContent.rectTransform.localPosition = StartPos;
        while (true)
        {
            DisplayContent.rectTransform.position += new Vector3(-Speed, 0, 0);

            if (DisplayContent.rectTransform.localPosition.x <= 0)
            {
                DisplayContent.rectTransform.localPosition = StartPos;
            }
            yield return new WaitForEndOfFrame();
        }
    }

协程开启的测试

重复开启协程:

非重复情况:计数变量只输出一次,协程只运行一次;

``

public class CoroutineTest : MonoBehaviour
{
    IEnumerator enumerator;
    int testNum;
    void Start()
    {
        enumerator = TestCoroutine();
        StartCoroutine(enumerator);//指定了具体的枚举器变量参与协程;

    }

    IEnumerator TestCoroutine()
    {
        Debug.Log("协程运行" + testNum++);
        yield break;
    }
}

重复情况:计数变量只输出一次,协程只运行一次;所以多次开启同一个Coroutine是不会造成多协程同时运行的;
    void Start()
    {
        enumerator = TestCoroutine();
        StartCoroutine(enumerator);//指定了具体的枚举器变量参与协程;
        StartCoroutine(enumerator);//指定了具体的枚举器变量参与协程;
        StartCoroutine(enumerator);//指定了具体的枚举器变量参与协程;
        StartCoroutine(enumerator);//指定了具体的枚举器变量参与协程;

    }

执行StopCoroutine方法:

当前帧停止协程:我加入了循环,计数变量输出一次,协程运行一次;所以一旦开启协程,当前帧无法停止;很像是doWhile:至少执行一次;
 void Start()
 {
     enumerator = TestCoroutine();
     StartCoroutine(enumerator);//指定了具体的枚举器变量参与协程;
     StopCoroutine(enumerator);//指定了具体的枚举器变量参与协程;
 }
 
   IEnumerator TestCoroutine()
  {
      while (true)
      {
          Debug.Log("协程运行" + testNum++);
          yield return new WaitForEndOfFrame();
      }

     // yield break;
  }
写一个邪教的,当前帧开启关闭,开启关闭,计数变量如何输出呢?
    void Start()
    {
        enumerator = TestCoroutine();
        StartCoroutine(enumerator);//指定了具体的枚举器变量参与协程;
        StopCoroutine(enumerator);//指定了具体的枚举器变量停止协程;
        StartCoroutine(enumerator);//指定了具体的枚举器变量参与协程;
        StopCoroutine(enumerator);//指定了具体的枚举器变量停止协程;
    }

输出内容如下:运行两次,输出0,1;
![[Pasted image 20231130114204.png]]
所以说,这是很有趣的,和dowhile很像;

不指定协程对象,也就是不主动创建唯一的协程实例会有什么后果?直接测试;

    void Start()
    {
        enumerator = TestCoroutine();
        StartCoroutine(TestCoroutine());//指定了具体的枚举器返回值参与协程;
       // StopCoroutine(TestCoroutine());//指定了具体的枚举器返回值停止协程;
        StartCoroutine(TestCoroutine());//指定了具体的枚举器返回值参与协程;
       // StopCoroutine(TestCoroutine());//指定了具体的枚举器返回值停止协程;
    }

    IEnumerator TestCoroutine()
    {
        while (true)
        {
            Debug.Log("协程运行" + testNum++);
             yield break;
           // yield return new WaitForEndOfFrame();
        }
    }

``回顾一下第一次当前帧开启两次协程的时候输出的结果唯一,但是这次测试输出结果有两个,就是协程函数被执行了两次;原因是这两次执行的协程实例并不是同一个,但是函数调用的却是同一个,TestCoroutine()方法被自然而然的调用了两次;而第一次我定义了一个enumerator的变量接收了TestCoroutine()方法的返回值,enumerator是唯一的,所以创建的协程实例也是唯一的,所以开发的时候还是要尽量在开启协程的时候指定唯一的开启协程的参数;

也就是我用StartCoroutine (string methodName)开启,必须用public void StopCoroutine (string methodName);来关闭;不能用别的方式,否则无法停止协程;
//开启
public void StartCoroutine (string methodName);

public void StartCoroutine (IEnumerator routine);

public void StartCoroutine (Coroutine)
//关闭
public void StopCoroutine (string methodName);

public void StopCoroutine (IEnumerator routine);

public void StopCoroutine (Coroutine)

StartCoroutine之后,再启动协程,会从头开始执行吗?

    void Start()
    {
        enumerator = TestCoroutine();
      //  StartCoroutine(TestCoroutine());//指定了具体的枚举器变量参与协程;
       // StopCoroutine(TestCoroutine());//指定了具体的枚举器变量停止协程;

        StartCoroutine(enumerator);
        StopCoroutine(enumerator);//指定了具体的枚举器变量停止协程;
       
    }

    private void Update()
    {
        if (istuck)
            return;
        istuck = true;
        StartCoroutine(enumerator);
        StopCoroutine(enumerator);
    }


    IEnumerator TestCoroutine()
    {
        while (true)
        {
            Debug.Log("协程运行" + testNum++);
             //yield break;
             yield return new WaitForEndOfFrame();

            Debug.Log("协程运行" +"第一次");
            yield return new WaitForEndOfFrame();

            Debug.Log("协程运行" + "第二次");
            yield break;
        }

        
    }
``协程不会从头执行会从上一次中断处继续执行;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值