python基礎===進程,線程,協程的區別(轉)


本文轉自:http://blog.csdn.net/hairetz/article/details/16119911  

  • 進程擁有自己獨立的堆和棧,既不共享堆,亦不共享棧,進程由操作系統調度。
  • 線程擁有自己獨立的棧和共享的堆,共享堆,不共享棧,線程亦由操作系統調度(標准線程是的)。
  • 協程和線程一樣共享堆,不共享棧,協程由程序員在協程的代碼里顯示調度。

進程和其他兩個的區別還是很明顯的。

打個比方吧,假設有一個操作系統,是單核的,系統上沒有其他的程序需要運行,有兩個線程 A 和 B ,A 和 B 在單獨運行時都需要 10 秒來完成自己的任務,而且任務都是運算操作,A B 之間也沒有競爭和共享數據的問題。現在 A B 兩個線程並行,操作系統會不停的在 A B 兩個線程之間切換,達到一種偽並行的效果,假設切換的頻率是每秒一次,切換的成本是 0.1 秒(主要是棧切換),總共需要 20 + 19 * 0.1 = 21.9 秒。如果使用協程的方式,可以先運行協程 A ,A 結束的時候讓位給協程 B ,只發生一次切換,總時間是 20 + 1 * 0.1 = 20.1 秒。如果系統是雙核的,而且線程是標准線程,那么 A B 兩個線程就可以真並行,總時間只需要 10 秒,而協程的方案仍然需要 20.1 秒。

    #!/usr/bin/python
    # python thread.py
    # python -m gevent.monkey thread.py

    import threading class Thread(threading.Thread): def __init__(self, name): threading.Thread.__init__(self) self.name = name def run(self): for i in xrange(10): print self.name threadA = Thread("A") threadB = Thread("B") threadA.start() threadB.start()

   
python thread.py

A B A B ...

那么總共發生了 20 次切換:主線程 -> A -> B -> A -> B …

 #!/usr/bin/python
    # python gr.py

    import greenlet def run(name, nextGreenlets): for i in xrange(10): print name if nextGreenlets: nextGreenlets.pop(0).switch(chr(ord(name) + 1), nextGreenlets) greenletA = greenlet.greenlet(run) greenletB = greenlet.greenlet(run) greenletA.switch('A', [greenletB])

greenlet 是 python 的協程實現。

python gr.py

此時發生了 2 次切換:主協程 -> A -> B

python -m gevent.monkey thread.py

gevent 是基於 greenlet 的一個 python 庫,它可以把 python 的內置線程用 greenlet 包裝,這樣在我們使用線程的時候,實際上使用的是協程,在上一個協程的例子里,協程 A 結束時,由協程 A 讓位給協程 B ,而在 gevent 里,所有需要讓位的協程都讓位給主協程,由主協程決定運行哪一個協程,gevent 也會包裝一些可能需要阻塞的方法,比如 sleep ,比如讀 socket ,比如等待鎖,等等,在這些方法里會自動讓位給主協程,而不是由程序員顯示讓位,這樣程序員就可以按照線程的模式進行線性編程,不需要考慮切換的邏輯。

gevent 版的命令發生了 3 次切換:主協程 -> A -> 主協程 -> B

再來說說 python 的線程,python 的線程不是標准線程,在 python 中,一個進程內的多個線程只能使用一個 CPU 。

如果使用 gevent 包裝后的線程,程序員就不必承擔調度的責任,而 python 的線程本身就沒有使用多 CPU 的能力,那么,用 gevent 包裝后的線程,取代 python 的內置線程,不是只有避免無意義的調度,提高性能的好處,而沒有什么壞處了嗎?

答案是否定的。舉一個例子,有一個 GUI 程序,上面有兩個按鈕,一個 運算 一個 取消 ,點擊運算,會有一個運算線程啟動,不停的運算,點擊取消,會取消這個線程,如果使用 python 的內置線程或者標准線程,都是沒有問題的,即便運算線程不停的運算,調度器仍然會給 GUI 線程分配時間片,用戶可以點擊取消,然而,如果使用 gevent 包裝后的線程就完蛋了,一旦運算開始,GUI 就會失去相應,因為那個運算線程(協程)霸着 CPU 不讓位。不單是 GUI ,所有和用戶交互的程序都會有這個問題。

 


免責聲明!

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



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