協程與yield

協程,又稱微線程或纖程,是一個比進程和線程更加輕量級的解決方案,現代編程語言基本上都支持。那麼協程究竟有什麼特色,它是如何運做的呢?

進程和線程之間的關係我在這篇文章中作了一下比較分析。線程是程序的運行流,全部指令從頭至尾按順序一一執行,進程則是包含線程的容器。在單核CPU中,永遠只有一條線程在運行,固然也只可能有一個進程運行,由操做系統內核負責進程和線程的切換。而協程是屬於用戶空間的,操做系統對其一無所知,由用戶本身去作調度。顯然用戶本身調度比經過使用一箇中斷讓操做系統調度會快不少,這就是協程快的祕訣了。php

那麼,協程到底是一種什麼樣的存在呢?上面說到線程是一條指令的執行流,那麼這個流的則由函數這些最小執行單元組成,函數則多是包涵或者調用關係,不管是那種,一個函數只有只能完畢,下一個函數才能被執行,例若有兩個函數A和B,A因爲某些緣由被阻塞,那麼B確定就不能運行。協程的出現就是爲了解決這個問題,函數能夠隨時中斷,去調用另外的函數。html

Python和PHP5.5以上版本(包含)中,能夠利用生成器中的yield在必定程度上實現協程。例如在一個車流量多的路口,攝像頭獲取車牌號,並保存到文本文件能夠這樣作:python

#!/usr/bin/env python
import random
def getNum(action):
    action.next()
    while True:
        num=random.randint(1000, 9999) #獲取車牌號,這裏隨機
        stored = action.send(num)
        if stored > 500:
            break
    action.close()
def storage():
    r=0
    while True:
        f=open("./car.txt","a")
        num = yield r
        print num
        if num:
            f.write(str(num)+"\n")
            r=r+1
    f.close()
if __name__ == "__main__":
    S=storage()
    getNum(S)
<?php
function getNum($action){
    while(1){
        $num=rand(1000,9999);
        $stored = $action->send($num);
        if($stored > 500){
            break;
        }
    }
}
function storage(){
    $r=0;
    while(1){
        $num=(yield $r);
        if($num){
            echo $num."\n";
            file_put_contents("./car.txt",$num."\n",FILE_APPEND);
            $r++;
        }
    }
}
$S=storage();
getNum($S);

 

yield這個關鍵字在不少語言中都有應用,在PHP和Python中,若是一個函數中含有yield,則這個函數會成爲一個生成器(Generator)。上面的例子中,函數之間相互調用並無在一個函數結束以後,另外一個函數纔開始運行,而是相互協做,因此稱爲」協程」,而非線程的搶佔式多任務。須要注意的是Python的yield須要用next來啓動,而PHP不須要。編程

yield只能在必定程度的實現協程,要更加深刻理解和使用協程,能夠嘗試使用gevent,gevent爲Python提供了比較完善的協程支持, 能幫助咱們自動切換協程,能夠得到極高的併發性能。併發

相關文章
相關標籤/搜索