首页 > 其他分享 >协程与迭代器

协程与迭代器

时间:2024-03-24 20:13:22浏览次数:16  
标签:return 迭代 yield DateTime 协程 Now public

自己实现unity的协程功能_c#实现类似unity的协程-CSDN博客

前天和同事聊天,聊起来协程,聊起原理,什么迭代器,什么MoveNext

几句话带过之后就算完了,事后再次想起,发现自己已经忘了具体细节,于是也打算写成博客,供自己以后回应

一句话概括

(yield外部的)(会运行的)代码行,会被放到MoveNext()中

(写在yield return后面的类或者参数)会变成Current,Update每帧去调Current(判断是否能MoveNext),倘若返回了false,就不做任何事,否则就MoveNext()+新的初始化

具体代码+注释

查看代码

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;

internal class Program
{
    static void Main(string[] args)
    {
        MyMonoBehaviour objMyMonoBehaviour = new MyMonoBehaviour();
        Console.WriteLine("Create MyMonoBehaviour" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
        objMyMonoBehaviour.StartCoroutine(CoroutineDetail());
        while (true)
        {
            objMyMonoBehaviour.Update();
            Thread.Sleep(100);
        }
    }

    static IEnumerator CoroutineDetail()
    {
        Console.WriteLine("yield return null start:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
        yield return null;
        Console.WriteLine("yield return null end:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));

        Console.WriteLine("wait 1.0 seconds start:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
        yield return new MyWaitForSeconds(1.0f);
        Console.WriteLine("wait 1.0 seconds end:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));

        Console.WriteLine("wait 2.0 seconds start:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
        yield return new MyWaitForSeconds(2.0f);
        Console.WriteLine("wait 2.0 seconds end:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
    }
}

public class MyMonoBehaviour
{
    public class RoutineInfo
    {
        //我的迭代器
        public IEnumerator routine;
        //迭代器当前需要比较的对象
        public MyYieldInstruction current;

        public bool IsCanMoveNext()
        {
            return current == null || current.IsCanMoveNext();
        }
    }

    //迭代器数据类List
    List<RoutineInfo> lstRoutine = new List<RoutineInfo>();

    public void StartCoroutine(IEnumerator routine)
    {
        //如果是空迭代器或者只能迭代一次的,直接返回
        if (routine == null || !routine.MoveNext()) return;

        //新建迭代数据类,管理该迭代器
        RoutineInfo objRoutineInfo = new RoutineInfo();
        lstRoutine.Add(objRoutineInfo);

        //初始化迭代数据类
        objRoutineInfo.routine = routine;
        SetRoutineInfo(ref objRoutineInfo);
    }

    //设置目标迭代器当前的迭代参数
    public void SetRoutineInfo(ref RoutineInfo objRoutineInfo)
    {
        //yield后面不是new了一个类嘛,存到迭代器的Current里了,要拿到类,就在这设置一下
        objRoutineInfo.current = objRoutineInfo.routine.Current as MyYieldInstruction;
    }

    public void Update()
    {
        //从后往前遍历,便于lstRoutine.RemoveAt(i)
        for (int i = lstRoutine.Count - 1; i >= 0; i--)
        {
            RoutineInfo item = lstRoutine[i];
            if (item == null) continue;

            if (!item.IsCanMoveNext()) continue;

            if (item.routine.MoveNext()) SetRoutineInfo(ref item);
            else lstRoutine.RemoveAt(i);//清除迭代完的迭代器
        }
    }
}

//抽象类+抽象方法,有其他类型的迭代器就继承这个,判断条件由自己去实现
public abstract class MyYieldInstruction
{
    public abstract bool IsCanMoveNext();
}

public class MyWaitForSeconds : MyYieldInstruction
{
    //在yield return时,记录等待时间,并用于后续的每次比较
    public float seconds;
    private DateTime beginTime;

    public MyWaitForSeconds(float seconds)
    {
        this.seconds = seconds;
        beginTime = DateTime.Now;
    }

    //MyWaitForSeconds的比较就是
    //1.在初始化时记录开始时间和等待时间
    //2.使用当前时间减去开始时间,得到时间差
    //3.使用时间差去和等待时间比较,如果时间差>等待时间,就表示可以MoveNext
    public override bool IsCanMoveNext()
    {
        TimeSpan deltaSeconds = DateTime.Now - beginTime;
        bool res = deltaSeconds.TotalSeconds > seconds;
        Console.WriteLine("MyWaitForSeconds类内部比较一次,结果为" + res);
        return res;
    }
}

输出:

标签:return,迭代,yield,DateTime,协程,Now,public
From: https://www.cnblogs.com/LateUpdate/p/18092741

相关文章

  • EANet:用于医学图像分割的迭代边缘注意网络
    EANet:用于医学图像分割的迭代边缘注意网络摘要引言相关工作方法看一下的论文EANet:Iterativeedgeattentionnetworkformedicalimagesegmentation–2022摘要医学图像的精确自动分割对临床诊断和分析有着重要的帮助。然而,由于(1)医学图像目标的尺度多样性和(2)医......
  • Day25 迭代器之Iterator底层
    Day25迭代器之Iterator底层一、迭代器1、概念:迭代器(Iterator)是一种用于遍历集合(Collection)元素的接口,它提供了统一的方式来访问集合中的元素,而不暴露集合的内部结构。通过迭代器,我们可以依次访问集合中的每个元素,进行遍历和操作。2、使用步骤:获取集合的迭代器:Iterat......
  • Python编程异步爬虫——协程的基本原理
    Python编程之异步爬虫协程的基本原理要实现异步机制的爬虫,自然和协程脱不了关系。案例引入先看一个案例网站,地址为https://www.httpbin.org/delay/5,访问这个链接需要先等5秒钟才能得到结果,这是因为服务器强制等待5秒时间才返回响应。下面来测试一下,用requests写一个遍历......
  • python之迭代器和生成器的使用方式
    下面我将分别介绍迭代器和生成器的使用示例:迭代器示例:迭代器是一种对象,它可以在遍历时逐个访问元素而不需要将所有元素加载到内存中。下面是一个简单的迭代器示例,该迭代器生成斐波那契数列的前n个数字:classFibonacciIterator:def__init__(self,n):self.n=......
  • 迭代器切片/itertools.islice/yield返回
    使用itertools.isliceitertools.islice允许您对迭代器进行切片操作,这是处理生成器切片的推荐方法。它不需要将生成器的所有元素加载到内存中,因此仍然保持了生成器的高效性。这里是如何使用islice来获取前四个元素的示例:fromitertoolsimportislice#假设dou.get_user_post返......
  • 在for循环中删除迭代器所指内容崩溃
    经常在网上看到“容器中删除的只要不是最后一个元素,循环就会崩溃”其实不然,经过测试;容器中使用迭代器循环访问,只要删除迭代器所指元素后,继续for,不管你删除的是第一个还是最后一个,或者中间的某一个,只要不跳出来,就会崩溃;首先,for循环,++或者--,都是在for循环体执行完一次后执行;所以当......
  • [GPT] swoole的协程和golang的协程有什么区别,哪个更好
    Swoole的协程和Golang(Go语言)的协程(Goroutine)在概念上都是为了实现轻量级的并发编程,但它们在具体实现、使用方式和性能特点上有所不同:实现原理:Golang协程(Goroutine):Go语言从语言层面内置了对协程的支持。Goroutine是由Go运行时系统管理的轻量级线程,它基于M:N调度模型......
  • TypeScript之Symbol和迭代器
    Symbols介绍自ECMAScript2015起,symbol成为了一种新的原生类型,就像number和string一样。symbol类型的值是通过Symbol构造函数创建的。letsym1=Symbol();letsym2=Symbol("key");//可选的字符串keySymbols是不可改变且唯一的。letsym2=Symbol("key");let......
  • 【python】(02)初识迭代器Iterator
    系列文章回顾【python】(01)初识装饰器Decorator【python】(02)初识迭代器Iterator文章目录一.迭代器的定义二.迭代器的作用三.实际代码示例四.使用注意事项五.常见问题迭代器是Python中非常重要的概念,通过灵活运用迭代器可以实现高效的数据遍历和处......
  • 每日一看大模型新闻(2024.1.20-1.21)英伟达新对话QA模型准确度超GPT-4,却遭吐槽:无权重代
    1.产品发布1.1韩国Kakao:推出多模态大模型Honeybee发布日期:2024.1.20KakaounveilsmultimodallargelanguagemodelHoneybee-TheKoreaTimes主要内容:韩国科技巨头Kakao今天宣布他们已经开发了一种名为“蜜蜂”(Honeybee)的多模态大语言模型。据Kakao称,“蜜蜂”能够同时......