Unity3D中的C#协程(概念、使用方法、底层原理)

这篇具有很好参考价值的文章主要介绍了Unity3D中的C#协程(概念、使用方法、底层原理)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

        Unity3D 中的协程是针对 Unity3D 框架和 C# 编程语言定制的,具有便捷的使用方式和良好的效率。其他语言Python、Lua等也支持协程,但是底层实现的细节可能不同。在 Unity3D 引擎中,协程被 Unity3D 引擎的主循环所驱动


协程概念

        协程(Coroutine)是一种编程概念,是一种轻量级的用户空间线程在 Unity3D 中被广泛用于处理异步操作、延迟执行和分帧处理等任务。协程在 Unity3D 中可以让程序员用类似于同步编码的样式来实现异步操作,从而使代码更易于阅读和理解。行非抢占式的任务切换。这些代码块也称为协程。


协程作用

        协程可以通过将一个复杂的任务分解成多个步骤来模拟异步处理,在每个帧之间“暂停”并将控制权返回给 Unity3D 主线程。这使得协程在特定的时间或条件的满足后恢复执行。协程通过让程序流程主动挂起yield和恢复,从而使你能够编写看似线性的代码,同时处理非阻塞性操作,如等待时间、访问网络资源等。协程的主要优点是可以在对等地位的特定代码块之间进协程在 Unity3D 中常用来处理任务的延迟(场景加载、异步加载AssetBundle等资源)、I/O操作、网络通信,因为它们可以防止阻塞主线程,从而确保游戏运行流畅。


协程的常用写法

// 下一帧再执行后续代码
yield return null;
yield return 0;
yield return 6;		// 任意数字

// 直接结束该协程的后续操作
yield break;

// 等待异步操作结束后再执行后续代码
yield return asyncOperation;

// 等待某个协程执行完毕后再执行后续代码
yield return StartCoroutine(某个协程函数);

// 等待某个函数完成后再执行后续代码
yield return Function();

// 等待帧结束(所有的摄像机和GUI被渲染完成后,在该帧显示在屏幕之前执行)
yield return new WaitForEndOfFrame();

// 等待 所有的Update函数完成的那一帧之后 一段指定的时间延迟(秒)之后继续执行
yield return new WaitForSeconds(0.3f);

// 等待下一次FixedUpdate开始时再执行后续代码
yield return new WaitForFiexdUpdate();

// 将协同执行直到 当前输入的参数(或者委托)为true的时候
yield return new WaitUntil();

// 将协同执行直到 当前输入的参数(或者委托)为false的时候
yield return new WaitWhile();
// for 循环,每帧
for(int i = 0; i < 10; i++)
{
    Debug.Log(i);
    yield return null;
}

// 下载网络资源
UnityWebRequest req = UnityWebRequest.Get("http://127.0.0.1:6080/game_map");
yield return req.Send();
Debug.Log("download success" + req.downloadedBytes);

// 异步加载AssetBundle
AssetBundle ab = AssetBundle.LoadFromMemory(req.downloadHandler.data);
AssetBundleRequest abReq = ab.LoadAssetAsync<GameObject>(Assets/Resources/GameObject.prefab);
yield return abReq;
GameObject obj = abReq.asset as GameObject;
ab.Unload(false);

协程的底层 IEnumerator 与 yield

        协程的调度完全由开发者控制,而不是由系统底层来管理

        在Unity底层,协程由MonoBehaviourStartCoroutine方法创建、启动和调度。当一个协程方法被调用时,Unity会将协程与一个迭代器一起添加到待处理队列。然后,Unity将在每一帧的Update方法中处理队列中的协程,直到协程完成或被停止。

        协程是基于迭代器IEnumerator和C#的yield关键字实现的。对于IEnumerator迭代器我的理解是,他是一个函数对象的一个容器。协程函数可以通过使用yield return关键字将任务分解成多个片段,保存上下文。简单来说就是,协程函数通过yield关键字可以帮我们抽出函数代码块(前一个yield与当前yield之间的代码块)生成一个函数放到IEnumerator容器,最后协程函数返回这个迭代器。协程就是将IEnumerator里的函数,每隔一帧依次执行一个,这通过IEnumerator接口的MoveNext()Current属性来实现,MoveNext()用于处理协程的下一个步骤,Current则表示当前的执行结果。

        协程就是将IEnumerator里引用的代码段,每隔一帧执行一次

// 模拟StartCoroutine
public IEnumerator nowEnum;
public void My_StartCoroutine(IEnumerator e)
{
    onwEnum = e;
}

void LateUpdate()
{
    if(nowEnum != null)
    {
        if(!nowEnum.MoveNext())
        {
            nowEnum = null;
        }
    }
}

        Unity3D 中的协程并不像传统的线程或者其他多任务实现那样涉及到堆栈指针、指令指针等底层上下文切换。相反,它依赖于 C# 编译器生成的迭代器和状态机,提供了一种轻量级的、基于语言特性实现的异步编程方式。但是值得注意的是,协程在 Unity3D 中并不是一个真正的多线程特性,它只是提供了一种编程模式,看起来具有异步的效果。在线程本身中(在 Unity3D 的主线程中),协程会按照指定的顺序、同步地执行。


Unity3D 中的协程与线程相比

虽然 Unity3D 中的协程和线程都是用来处理异步任务的,但它们之间有一些明显的区别:

  1. 实现方式:
    1. 协程是基于 C# 的 IEnumerator 接口实现的,可以视为一种伪异步编程方式;
    2. 线程是基于系统底层的多线程模型实现,能够运行在操作系统提供的不同的独立执行单元中,实现真正的多任务并行执行。
  2. 管理方式
    • 协程是用户级的概念,它们的创建、管理和调度主要是在用户程序中完成的。
    • 线程主要由操作系统进行管理和调度。当线程切换发生时,保存和恢复线程执行的上下文和状态是由操作系统内核来完成的。
  3. 上下文切换消耗:
    1. 协程的上下文切换消耗较小,因为它仅依赖 C# 编译器生成的状态机;
    2. 线程间的上下文切换消耗较大(需要保存和恢复堆栈指针、指令指针等),在多线程环境下可能会产生性能问题。
  4. CPU 利用:
    1. 协程运行在 Unity3D 的主线程上,任务执行是有序且在同一个线程中的,这意味着协程的任务不能充分利用多核 CPU 的优势;
    2. 线程是独立的执行单元,可在多核 CPU 上同时运行,更好地利用计算资源。
  5. 并发控制:
    1. 协程在同一时间只能运行一个任务,降低了并发问题的发生概率;
    2. 线程并行执行,需要考虑死锁、竞态条件等并发控制问题,可能需要使用互斥锁、信号量等机制进行同步和通信。
  6. 适用场景:
    1. 协程适用于需要分步执行、非密集计算类型的任务,例如延时、逐帧更新、网络请求等;
    2. 线程适用于较复杂、计算密集型、需要并行执行的任务,如图形渲染、大数据处理等。

        

        总之,协程和线程在 Unity3D 中有各自的优缺点,适用于不同的应用场景。根据项目需求,选择适当的异步策略对于性能和可维护性都至关重要。在 Unity3D 的协程方案中如果需要处理密集型任务可以结合 ThreadPool 或者 C# Task 类库,并在需要时使用线程安全的数据结构以确保正确并发操作。文章来源地址https://www.toymoban.com/news/detail-718986.html

到了这里,关于Unity3D中的C#协程(概念、使用方法、底层原理)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity3D WebGL平台使用WebSocket通信的方法和示例

          之前在WebGL平台和服务端交互的时候使用的是UnityWebRequest,通过WebAPI的方式进行交互,后来发现可以用WebSocket交互后就果断换了WebSocket。 一、Unity3D客户端 我在Unity端使用的是 NativeWebSocket NativeWebSocket下载地址 直接导入Unity即可, 下面是适配的代码,直接挂载在GameObject。

    2024年02月11日
    浏览(36)
  • C#的Random与Unity3D的Random.Range()

    目录 C#的Random Unity3D的Random.Range() 在C#中,Random类用于生成伪随机数。它位于System命名空间下,所以要在代码中使用Random类,需要添加以下using语句: 在创建Random对象时,可以选择使用当前时间作为种子,也可以指定一个整数值作为种子。如果使用相同的种子来创建Random对象,

    2024年02月16日
    浏览(28)
  • Unity3D实现第一人称移动,随鼠标转动视角+上楼梯(C#)

    第一人称移动: 1、在层级面板创建一个Capsule,命名为Player,将层级面板中的相机拖到Player下方 2、重置Player和摄像机的Transform数值(方便调整摄像机在Player上的位置),然后调整摄像机在Player上的位置 大概将摄像机放到Player眼睛的位置即可。 3、创建一个脚本,命名为Came

    2024年02月13日
    浏览(41)
  • Unity3D高级编程主程手记 学习笔记二:C#技术要点

    1.Untiy3D中C#的底层原理 Unity底层在运行C#程序时有两种机制:一种是Mono,另一种是IL2CPP。 Mono存在的目的是为了跨平台 ,因为最初C#只支持Windows。而IL可以看成是一种汇编语言且完全基于堆栈,必须运行在虚拟机上。也就是说C#会被编译器编译成IL,当需要他们时就会被实时的

    2024年02月08日
    浏览(43)
  • Unity3D C# 中foreach的GC产出(2023年带数据)

    注意:笔者有点被杠怕了…确实也不严谨,也怕看不到,所以开头这里加一句:foreach本身不会产生GC,产生GC的原因是foreach使用了迭代器Enumerator,而取决于容器的不同,有些迭代器的初始化会产生GCAlloc… 很多读者在听一些群内大佬谈话过程中可能会听说 foreach遍历集合会产生

    2024年02月16日
    浏览(36)
  • Unity3d Application中的所有目录以及含义

    本工程Asset的完整路径,测试输出Log:dataPath:E:/game_all/GameClient/Assets 本地可写区目录,测试输出Log:persistentDataPath:C:/Users/zhang/AppData/LocalLow/DefaultCompany/GameClient 本工程Asset/StreamingAssets目录,测试输出Log:streamingAssetsPath:E:/game_all/GameClient/Assets/StreamingAssets 本地可写区临时缓存目录

    2024年02月12日
    浏览(47)
  • Unity3D C#获取Texture2D像素数据IntPtr指针

    Unity3D调用C++库执行图像处理时,需要快速传递Texture2D纹理像素数据块,获取数据块C++指针(C#中用IntPtr表示) 代码如下 案例

    2024年02月15日
    浏览(45)
  • 如何将Unity3D中的脚本打包成为DLL类库?

    如果我们想把代码打成DLL,首先需要有一个Assembly和一个合理的代码目录结构规划。 1.将要归为一类的脚本放进同一个文件内,在该文件夹下右键创建一个Assembly Definition,默认它会将同文件夹以及子目录内的脚本归为一个Assembly。 2.在Editor下创建一个CompileDll脚本来将我们的脚

    2024年02月12日
    浏览(32)
  • Unity3D使用C#脚本修改TextMeshPro的内容(以显示系统时间为例)

    在网上找了很多都没有涉及到这个TextMeshPro内容修改,踩了很多坑,记录一下 特别是using TMPro; public TextMeshProUGUI Text; GetComponent();

    2024年02月11日
    浏览(29)
  • Unity3d C#实现场景编辑/运行模式下3D模型XYZ轴混合一键排序功能(含源码工程)

    在部分场景搭建中需要整齐摆放一些物品(如仓库中的货堆、货架等),因为有交互的操作在单个模型上,每次总是手动拖动模型操作起来也是繁琐和劳累。 在这背景下,我编写了一个在运行或者编辑状态下都可以进行一键排序模型的脚步。方便在场景搭建时,可以快速搭建

    2024年01月17日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包