協程的原理以及與線程的區別


1 什么是協程?

協程(coroutine)是一種程序運行的方式即在單線程里多個函數並發地執行.

A coroutine is a function that can suspend its execution (yield) until the given given YieldInstruction finishes.

個人簡單的理解是, 在協程中的函數, 如果執行過程中遇到了I/O密集型任務, 被給定的YieldInstruction(讓出指令)暫停執行(yield), 交出執行權到其他函數, 直到被給定的YieldInstruction(讓出指令)結束, 再繼續執行。

2 協程與線程的區別

  1. 由於協程的特性, 適合執行大量的I/O 密集型任務, 而線程在這方面弱於協程
  2. 協程涉及到函數的切換, 多線程涉及到線程的切換, 所以都有執行上下文, 但是協程不是被操作系統內核所管理, 而完全是由程序所控制(也就是在用戶態執行), 這樣帶來的好處就是性能得到了很大的提升, 不會像線程那樣需要在內核態進行上下文切換來消耗資源,因此協程的開銷遠遠小於線程的開銷
  3. 同一時間, 在多核處理器的環境下, 多個線程是可以並行的,但是運行的協程的函數卻只能有一個其他的協程的函數都被suspend, 即協程是並發的
  4. 由於協程在同一個線程中, 所以不需要用來守衛臨界區段的同步性原語(primitive)比如互斥鎖、信號量等,並且不需要來自操作系統的支持
  5. 在協程之間的切換不需要涉及任何系統調用或任何阻塞調用
  6. 通常的線程是搶先式(即由操作系統分配執行權), 而協程是由程序分配執行權

3 協程的原理

當出現IO阻塞的時候,由協程的調度器進行調度,通過將數據流立刻yield掉(主動讓出),並且記錄當前棧上的數據,阻塞完后立刻再通過線程恢復棧,並把阻塞的結果放到這個線程上去跑,這樣看上去好像跟寫同步代碼沒有任何差別,這整個流程可以稱為coroutine,而跑在由coroutine負責調度的線程稱為Fiber。比如Golang里的 go關鍵字其實就是負責開啟一個Fiber,讓func邏輯跑在上面。

由於協程的暫停完全由程序控制,發生在用戶態上;而線程的阻塞狀態是由操作系統內核來進行切換,發生在內核態上。
因此,協程的開銷遠遠小於線程的開銷,也就沒有了ContextSwitch上的開銷。

4 協程的應用場景

協程的應用場景主要在於 :I/O 密集型任務

這一點與多線程有些類似,但協程調用是在一個線程內進行的,是單線程,切換的開銷小,因此效率上略高於多線程;

當程序在執行 I/O 時操作時,CPU 是空閑的,此時可以充分利用 CPU 的時間片來處理其他任務;

在單線程中,一個函數調用,一般是從函數的第一行代碼開始執行,結束於 return 語句、異常或者函數執行(也可以認為是隱式地返回了 None );

有了協程,我們在函數的執行過程中,如果遇到了I/O密集型任務,函數可以臨時讓出控制權,讓 CPU 執行其他函數,等 I/O 操作執行完畢以后再收回其他函數的控制權.

參考來源

https://docs.unity3d.com/540/Documentation/ScriptReference/Coroutine.html

https://zh.wikipedia.org/wiki/協程

https://stackoverflow.com/questions/553704/what-is-a-coroutine

https://juejin.cn/post/6844903921471717389

https://www.cnblogs.com/Survivalist/p/11527949.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM