Python 多執行緒 多程序 協程 yield
python中多執行緒和多程序的最大區別是穩定性和效率問題
多程序互相之間不影響,一個崩潰了不影響其他程序,穩定性高
多執行緒因為都在同一程序裡,一個執行緒崩潰了整個程序都完蛋
多程序對系統資源開銷大,多執行緒對系統資源開銷小,所以這方面來說多執行緒會比多程序快一點點
關於執行緒和程序的詳細使用方法這裡有https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014319272686365ec7ceaeca33428c914edf8f70cca383000
等看完協程再補上
i/o密集型任務瓶頸都在網路,磁碟這些地方,適合用指令碼語言進行多工操作
3.協程
子程式呼叫總是一個入口,一次返回,呼叫順序是明確的。而協程的呼叫和子程式不同。
協程看上去也是子程式,但執行過程中,在子程式內部可中斷,然後轉而執行別的子程式,在適當的時候再返回來接著執行。
協
程最大的優勢是高執行效率,因為子程式切換不是執行緒切換,而是由程式自己控制,沒有切換執行緒的開銷
不需要多執行緒鎖
協程是建立在生成器基礎上的,所以需要先理解迭代器生成器!!!
在一個執行緒裡面不等待IO操作返回的結果,通過訊息輪詢來發送一個IO操作的請求後就執行其他的,等IO操作返回結果訊息了再處理.這個不死等的方式不需要多執行緒多程序,在一個執行緒裡實現,大大的提高了執行效率
對序列,字典,檔案都可以使用iter()方法生成可迭代物件,然後用next()方法訪問,這種東西咱們叫迭代器,一般用for迴圈讀出內容
生成器是可迭代的
簡單的生成器
my_generator = (x*x for x in range(4))
1
dir(my_generator ) 裡面有iter()和next()屬性,說明生成器是迭代器,可以用for迴圈讀取內部的值
>>> for i in my_generator:
... print i
...
0
1
4
9
>>> for i in my_generator:
... print i
...
當第一遍迴圈的時候,將 my_generator 裡面的值依次讀出並列印,但是,當再讀一次的時候,就發現沒有任何結果。
生成器my_generator = (x*x for x in range(4))和列表解析式my_list = [x*x for x in range(4)]有啥不一樣的地方呢,列表是先劃分出記憶體來放列表中的資料的,生成器是用到的時候再申請記憶體,針對大量值的時候,列表佔記憶體較多,迭代器(生成器是迭代器)的優勢就在於少佔記憶體,還有一點區別就是上面那個for迴圈讀取內部的值,列表是可以反覆取值的,不像生成器指標到最後沒有了就不走了,列表的記憶體劃分好了,每次想取值都可以
>>> for i in my_list:
... print i
...
0
1
4
9
>>> for i in my_list:
... print i
...
0
1
4
9
yield
python中有個詞yield ,這傢伙尼瑪是生成器的標誌
比如
def g():
yield 0
yield 1
yield 2
lalalal = g()
print type(lalalal)
print dir(lalalal)
#輸出
<type 'generator'>
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'next', 'send', 'throw']
有iter和next,說明是迭代器,用lalalal.next()可以取值的
從上面的例子可以明白,含有yield關鍵字的函式返回值是一個生成器型別的物件,也是迭代器
我們任性的吧含有yield語句的函式叫做生成器,生成器是一種用普通函式語法定義的迭代器,反正記住,普通函式只要用了yield就變態成為生成器了,當然生成器具備迭代器屬性
我們來看看在函式裡 yield和return的具體區別
def r_return(n):
print "You taked me."
while n > 0:
print "before return"
return n
n -= 1
print "after return"
rr = r_return(3)
print rr
#輸出
You taked me.
before return
3
#可以看出來,普通函式遇到return將值返回玩後,函式就不往下繼續執行了
#再看用yield將函式變為generator生成器之後的樣子
def r_return(n):
print "You taked me."
while n > 0:
print "before return"
yield n
n -= 1
print "after return"
rr = r_return(3)
print rr.next()
print rr.next()
print rr.next()
#輸出
You taked me.
before return
3
after return
before return
2
after return
before return
1
#可以看出,用了yield比return好啊,返回完值(迭代一次),還可以再接著執行後面的內容(迭代第二次,第三次),直到跳出迴圈(沒有可迭代的東西了)
一般的函式,都是止於 return。作為生成器的函式,由於有了 yield,則會遇到它掛起,如果還有 return,遇到它就直接丟擲 SoptIteration 異常而中止迭代。
send
上面的生成器都是固定的,肚子裡有啥就輸出什麼,自從python2.5之後,生成器有了一個新的特性,就是send方法,用它能直接往生成器的肚子裡面傳遞資料了,讓生成器不再是固定輸出了
使用send可以接受一個外部傳入的變數,然後根據變數內容計算結果之後返回,咱們之後要說的協程就是靠生成器函式的這個特性
def repeater():
n=None
while 1:
n = (yield n)
r= repeater()
r.send(None)
print r.send("new friend come in")
print r.send("tseeee")
#輸出
new friend come in
tseeee
說下流程
這裡和傳統函式呼叫不一樣,敲黑板,要通過r.send(None)(ps:如果用了send起手必須傳None)或者r.next()或者next(r)來啟動生成器函式,並進行到第一個yield語句結束的位置.此時,執行完了yield這一行語句,這個時候括號裡的yield n返回初始值0,返回值n=0
然後send(“new friend come in”)這裡會傳入new friend come in,從下一行開始繼續執行,並回到while頭部,執行yield n這一行返回n=new friend come in了之後又停下來了,
.再執行r.send(“tseeee”),重複上一步,執行到yield n這一行返回n=tseeee之後再一次停下來
---------------------
作者:Peace & Love
來源:CSDN
原文:https://blog.csdn.net/u013205877/article/details/77429518?utm_source=copy
版權宣告:本文為博主原創文章,轉載請附上博文連結!