最近東西積攢了太多,感受再不寫進來就要炸了。python
相關的python包有幾個,好比thread包,到py3改爲_thread,而thread有一些問題使得不是很好用。通用的包叫threading。最近都是在用這個。安全
須要注意的點有生成實例好比t = threading.Thread(target=xxx, args=(xx,)),裏面有兩個參數,第一個是目標函數,第二個是相關的參數,注意類型。多線程
而後就是start啓動,join等待多線程實行完成這兩個方法。ide
#僞代碼 t1 = threading.Thread(target=fun1, args=("函數參數 1",)) t1.start() t2 = threading.Thread(target=fun2, args=("函數參數1", "函數參數2")) t2.start() #等待線程 t1.join() t2.join()
繼承threading.Thread使用,須要重寫run函數。函數
class MyThread(threading.Thread):
def __init__(self, arg):
super(MyThread, self).__init__()
self.arg = arg
def run(self):
time.sleep(2)
其餘經常使用屬性和方法有:工具
threading.currentThread:返回當前線程變量this
threading.enumerate:返回一個包含正在運行的線程的list,正在運行的線程指的是線程啓動後,結束前的狀態spa
threading.activeCount: 返回正在運行的線程數量,效果跟 len(threading.enumerate)相同操作系統
threading.timer: 定時器,利用多線程在指定時間後啓動一個功能線程
thr.setName: 給線程設置名字
thr.getName: 獲得線程的名字
守護線程:daemon:即若是將子線程設置成守護線程,則子線程會在主線程結束的時候自動退出,通常認爲,守護線程不中要或者不容許離開主線程獨立運行
而守護線程可否有效果跟環境相關
t1 = threading.Thread(target=fun, args=() ) # 社會守護線程的方法,必須在start以前設置,不然無效 t1.setDaemon(True) #t1.daemon = True t1.start()
由於線程之間有共享狀態(資源),會有一些諸如死鎖或者同步的問題。解決方法也是大同小異,這些python裏都給出了
相應的工具。好比本身設置一個鎖/信號燈。用semphore變量,還有可重入鎖解鎖遞歸的時候申請鎖的問題等等。
線程安全不安全變量list,set,dict,安全變量queue等。
替代無非是用進程或者魔改的線程包,諸如subprocess使用進程,multiprocessing用threading派生出來的,使用子進程,可使用多核或多CPU
還有一個current.future待會兒寫
使用的就是上面提到的線程替代方案multiprocessing,方法和threading差很少,multiprocessing.Process(target=xxx, args=(xx,)),而後一樣也能夠繼承後使用,實現方式相似多線程
還有一個就是pid和ppid,即進程ID和父進程ID,還有其餘常見的內容好比子進程和父進程共享資源啊,而子線程有本身獨立的棧空間啊之類的就不詳細描述了
還有其餘的諸如生產者-消費者模型,讀者-寫者模型等等。和上面的同樣,也不贅述了,操做系統書裏都有,寫在這沒什麼意義。
首先來寫一下協程的定義:協程是爲非搶佔式多任務產生子程序的計算機程序組件, 協程容許不一樣入口點在不一樣位置暫停或開始執行程序。
在這以前先寫兩個
有兩個概念,一是可迭代對象Iterable,二是迭代器Iterator
Iterable能夠用於for循環,二Iterator不只能夠用於for循環還能被next函數調用,能夠用isinstance函數判斷,好比list是可迭代的。
from collections import Iterable l = [1,2,3,4] isinstance(l, Iterable)
out:True
二者之間還能夠經過iter函數轉換
from collections import Iterator isinstance(iter('abc'), Iterator)
out:True
好比最多見的生成器有L = [x * x for x in range(10)],
g = (x * x for x in range(10))
這些生成列表,元組的方法
本質是一個函數/方法,每次調用next的時候計算下一個值,最後會拋出StopIteration異常。
函數中包含yield,則叫generator
next調用,遇到yield返回
# 在函數odd中,yield負責返回 def odd(): print("Step 1") yield 1 print("Step 2") yield 2 print("Step 3") yield 3 # odd() 是調用生成器 g = odd() one = next(g) print(one) two = next(g) print(two) three = next(g) print(three)
out:Step 1
1
Step 2
2
Step 3
3
是的,協程和生成器很像,使用yield和send。目的是合理調用各類系統資源和進行協同工做。協程之間切換耗費也很低
協程有四個狀態:
GEN_CREATED:等待開始執行
GEN_RUNNING:解釋器正在執行
GEN_SUSPENED:在yield表達式處暫停
GEN_CLOSED:執行結束
def simple_coroutine(a): print('-> start') b = yield a # 把A丟出來給aa print('-> recived', a, b) c = yield a + b print('-> recived', a, b, c) # runc sc = simple_coroutine(5) aa = next(sc) # 預激,準備好執行協程,程序走到yield停下 print(aa) bb = sc.send(6) # 5 ,6 把參數6發給b print(bb) cc = sc.send(7) # 5, 6, 7 print(cc)#執行不到,拋出StopIteration異常
out:
-> start
5
-> recived 5 6
11
-> recived 5 6 7
以前說過,最後會拋出一個StopIteration異常,未處理的異常會向上冒泡,傳給next函數或send函數的調用方。終止協程能夠發送某個哨符,讓協程退出,好比內置的None和Ellipsis等常量
還有兩個和異常相關的方法generator.throw(Exctpiton)和generator.close()
大概做用就是前一個會在暫停的yield出拋出指定的異常。若是生成器處理了該異常,則代碼會執行到下一個yield
而產出的值(value,異常的一個屬性)會成爲調用 generator.throw方法獲得的返回值。沒處理則往上冒泡。
第二個的做用是導致生成器在暫停的 yield 表達式處拋出 GeneratorExit 異常。若是生成器沒有處理這個異常,或者拋出了 StopIteration 異常(一般是指運行到結尾),調用方不會報錯。
若是收到 GeneratorExit 異常,生成器必定不能產出值,不然解釋器會拋出RuntimeError 異常。生成器拋出的其餘異常會向上冒泡,傳給調用方。
如下是找到的一段事例代碼
class DemoException(Exception): """ custom exception """ pass def handle_exception(): print('-> start') while True: try: x = yield except DemoException: print('-> run demo exception') else: print('-> recived x:', x) raise RuntimeError('this line should never run') he = handle_exception() next(he) he.send(10) # recived x: 10 he.send(20) # recived x: 20 he.throw(DemoException) # run demo exception he.send(40) # recived x: 40 he.close()
相對於yield,yield from就至關於在調用方和生成器之間多了一層「通道」相似的代理。(又或者說在主線程和協程之間)
使用的渠道:好比委派生成器。
1,定義一個生成器(含yield)能夠一次次的接收調用方傳來的值(經過yield)和return回去處理後的值
2,定義個委派生成器,只須要yield from 生成器便可使用並接收值
3,調用委派生成器使用