C# & Unity 同步/异步编程和多线程什么关系?async/await和coroutine又是什么?

目录 不用模板生成的目录怎么这么丑啊

1.同步?异步?多线程?

2.async/await和coroutine?

证明

单线程中的同步/异步

多线程中的同步异步

1.同步?异步?多线程?

首先,你需要知道什么是同步编程,什么是异步编程

同步编程:所有代码按顺序执行,直到当前任务完成后才开始下一个任务

异步编程:代码可以在等待某些任务完成时继续执行其他任务

其次,你需要知道什么是多线程

**多线程:**是一种并发编程技术,允许一个程序同时执行多个线程

好,既然你能明白概念,说明你非常聪明,可以直接上第一个结论了

当然不懂也没关系,先有个印象我会说明为什么

2.async/await和coroutine?

我直接指名加油站,看懂了就行,二者都是异步处理的解决方法

async/await: async/await 用法,看这一篇就够了_async await用法-CSDN博客

coroutine: unity保姆级教程之协同程序_unity 协同程序实现原理-CSDN博客

请看下图结论

证明

单线程中的同步/异步

所有代码按顺序执行,直到当前任务完成后才开始下一个任务

举一个我家老太太都会写的例子

cs 复制代码
public class Single : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Func1();
        Func2();
    }

    void Func1()
        {
        Debug.Log("这是函数1 所需要执行的话");
    }
    void Func2() {
        Debug.Log("这是函数2 所需要执行的话");
    }
}

结果,注意时间

就相当于如此

代码可以在等待某些任务完成时继续执行其他任务

用协程函数

cs 复制代码
public class Single : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        StartCoroutine(Wait());
    }
    IEnumerator Wait()
        {
        Func1();
        yield return new WaitForSeconds(1.0f);
        Func2 ();
    }

    void Func1()
        {
        Debug.Log("这是函数1 所需要执行的话");
    }
    void Func2() {
        Debug.Log("这是函数2 所需要执行的话");
    }
}

注意时间

用async/await

cs 复制代码
public class Single : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Wait();
    }
    async void Wait() {
        Func1();
        await Task.Delay(1000); // 等待1秒
        Func2();
    }

结果当然是毫不意外

二者用图解 皆是如此

牢记这句话:代码可以在等待某些任务完成时继续执行其他任务

我可以在这1s打个胶还是什么都行,是不是非常严谨

多线程中的同步异步

多线程会遇到一个问题,就是新开的线程是独立的,并不会受到启动顺序的影响

比如:

cs 复制代码
  void Start()
  {
      Thread t1 = new Thread(Func1);
      Thread t2 =new Thread(Func2);
      t1.Start();
      t2.Start();
  }

那么就会出现这种情况:

即:有时候会是func1先执行,有时候会使func2先执行

那么要是使其实现同步的话,就需要加一个小小的类ManualResetEvent 类 (System.Threading) | Microsoft Learn

这样就可以实现,所有代码按顺序执行,直到当前任务完成后才开始下一个任务

cs 复制代码
public class Single : MonoBehaviour
{
    ManualResetEvent resetEvent = new ManualResetEvent(false);
    // Start is called before the first frame update
    void Start()
    {
        Thread t1 = new Thread(Func1);
        Thread t2 =new Thread(Func2);
        t1.Start();
        t2.Start();
    }

    void Func1()
        {
        Debug.Log("这是函数1 所需要执行的话");
        resetEvent.Set();
    }
    void Func2() {
        resetEvent.WaitOne();
        Debug.Log("这是函数2 所需要执行的话"); 
    }
}

另外你需要注意的一个点就是在unity中,其有自己的一个主线程用于执行生命周期函数,图解如下:

代码可以在等待某些任务完成时继续执行其他任务

cs 复制代码
public class Single : MonoBehaviour {
    // TaskCompletionSource 用于在异步任务之间传递信号
    private TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();

    async void Start() {
        Task t1= Func1();
        Debug.Log("看看这句话是在哪执行的1");
        Task t2 = Func2();
        Debug.Log("看看这句话是在哪执行的2");
        // 等待两个任务都完成
        await Task.WhenAll(t1, t2);
       
    }

    async Task Func1() {
        Debug.Log("这是函数1 所需要执行的话");

        // 设置 TaskCompletionSource 的结果,通知 Func2 可以继续执行
        tcs.SetResult(true);
    }

    async Task Func2() {
        // 等待 Func1 完成
        await tcs.Task;
        // 延迟一秒
        await Task.Delay(1000);
        Debug.Log("这是函数2 所需要执行的话");
    }
}

这我就不得不多说两句了,在这段代码中unity有自己的主线程,而t1和t2是副线程

当调用t1和t2时,这两个线程会在后台并行执行,而主线程会继续执行后续的代码。主线程和工作线程之间是并行运行的,互不阻塞

协程同理

cs 复制代码
public class Single : MonoBehaviour {
    Thread t1;
    Thread t2;
   void Start() {
        t1 = new Thread(Func1);
        t2 = new Thread(Func2);
        Debug.Log("看看这句话输出在哪里1");
        StartCoroutine(wait());
        Debug.Log("看看这句话输出在哪里2");
    }

    IEnumerator wait()
        { 
    t1.Start();
    yield return new WaitForSeconds(1.0f);
     t2.Start ();
    }
    // 异步方法 Func1
    void Func1() {
        // 输出调试信息
        Debug.Log("这是函数1 所需要执行的话");

    }

    // 异步方法 Func2
    void Func2() {

        Debug.Log("这是函数2 所需要执行的话");
    }
}

输出结果很意思,这明显不是按照顺序来的

更加证明了这是异步的,记住:代码可以在等待某些任务完成时继续执行其他任务

相关推荐
逝水无殇6 小时前
C# 文件的输入与输出详解
开发语言·数据库·后端·c#
这是个栗子7 小时前
前端开发中的常用工具函数(八)
开发语言·前端·javascript
凤凰院凶涛QAQ8 小时前
《Java版数据结构 & 集合类剖析》栈与队列:“push/pop 是栈的灵魂,offer/poll 是队列的骨架——四组 API,两种人生”
java·开发语言·数据结构
研☆香8 小时前
为什么变量声明在赋值前也能使用?—— 深入理解 JavaScript 变量提升与作用域
开发语言·前端·javascript
右耳朵猫AI8 小时前
PHP周刊2026W28 | 安全更新、Laravel 13.18、Twig 3.28
开发语言·php·laravel
second608 小时前
第一部分:快速上手 —— 建立 C++ 基本语法与编程范式
开发语言·c++
郝学胜-神的一滴8 小时前
算法实战:最小k个数——大顶堆的优雅解法
开发语言·数据结构·c++·python·程序人生·算法·排序算法
bksczm8 小时前
linux之线程概念和控制
linux·开发语言·c++
JackieZhengChina9 小时前
零依赖轻量级JS悬浮提示插件title2tip-js的使用教程
开发语言·javascript·ecmascript
hehelm9 小时前
Linux网络编程—TCP字典翻译系统
linux·开发语言·网络·c++·tcp/ip