协程的内存开销非常低。与线程相比,协程只需要少量的内存来维护其状态和堆栈。
一个线程通常需要分配 1MB 左右的堆栈空间,如果是 300 个线程就需要 300MB 左右的虚拟内存。
而一个协程的堆栈则是动态增长的,初始分配的内存非常小,通常在 2KB 左右,整整差了 500 倍,这也是为什么说协程是轻量级的。
由于协程的轻量级特性,一个应用程序可以同时运行运行大量的协程,从而实现高并发性。协程的调度是由程序控制的,可以在一个线程上高效地执行多个协程。
而线程的数量受限于系统资源,一个线程初始栈大小就有 1MB,300 个线程就需要 300 MB 左右的虚拟内存,开的越多越容易出现 OOM。
所以当涉及到大量并发的时候,使用协程性能更好。
说到并发编程,不得不说并发安全,线程一般是通过锁来保证并发安全的,实现起来比较复杂,容易出现死锁的情况,也会增加上下文切换的开销。
协程切换通常不需要使用锁机制,因为协程在单线程环境中运行时不会出现竞争条件。
协程的上下文切换开销非常低。协程切换是在用户空间进行的,不涉及操作系统内核的调度。这意味着切换协程时无需进行系统调用,从而减少了进入和退出内核态的开销,而线程切换涉及到内核态的转换,开销比较大。
协程的上下文切换只需要保存和恢复少量的状态信息,如程序计数器、少量寄存器和堆栈指针。线程切换则需要保存和恢复更多的状态信息,包括所有寄存器、线程堆栈、线程局部存储等,导致上下文切换开销较高。
协程的创建和销毁速度非常快。创建一个协程的开销仅仅是分配一小段内存初始化其状态,而线程的创建需要操作系统分配资源,初始化线程上下文等复杂操作,耗时较长。
协程采用非阻塞的执行模型。它们可以挂起自身而不阻塞线程,从而避免了线程阻塞带来的资源浪费和性能问题。协程挂起时,其他协程可以继续执行,从而提高了资源利用率和响应速度。
协程简化了异步编程。传统的异步编程需要使用回调、Future 等复杂的机制,而协程通过挂起和恢复机制,使得异步代码可以像同步代码一样编写,减少了代码复杂度和错误率。