標籤:thread name ima tor 結果 turn 產生器 alt try
1 multiprocessing模組
(1.)直接匯入from multiprocessing import Processimport osimport timedef info(name): print("name:",name) print(‘parent process:‘, os.getppid()) print(‘process id:‘, os.getpid()) print("------------------")def foo(name): info(name) time.sleep(50)if __name__ == ‘__main__‘: info(‘main process line‘) p1 = Process(target=info, args=(‘alvin‘,)) p2 = Process(target=foo, args=(‘egon‘,)) p1.start() p2.start() p1.join() p2.join() print("ending")time.sleep(100)>>name: main process lineparent process: 16976process id: 18456------------------name: alvinparent process: 18456process id: 19884------------------name: egonparent process: 18456process id: 19112------------------ending
(2.)建立類的方法
構造方法:
Process([group [, target [, name [, args [, kwargs]]]]])
group: 線程組,目前還沒有實現,庫引用中提示必須是None;
target: 要執行的方法;
name: 進程名;
args/kwargs: 要傳入方法的參數。
執行個體方法:
is_alive():返回進程是否在運行。
join([timeout]):阻塞當前上下文環境的進程程,直到調用此方法的進程終止或到達指定的timeout(選擇性參數)。
start():進程準備就緒,等待CPU調度
run():strat()調用run方法,如果執行個體進程時未制定傳入target,這star執行t預設run()方法。
terminate():不管任務是否完成,立即停止背景工作處理序
屬性:
daemon:和線程的setDeamon功能一樣
name:進程名字。
pid:進程號。
2 協程
協程的優點:
(1) 由於單線程不存在切換
(2) 不再有任何鎖的概念
yield是最基本的攜程函數沒有辦法監聽到IO,進行切換可以儲存到資料的狀態通過send方法來運行import time# 注意到consumer函數是一個generator(產生器):# 任何包含yield關鍵字的函數都會自動成為產生器(generator)對象def consumer(): r = ‘‘ while True: n = yield r if not n: return print(‘[CONSUMER] ←← Consuming %s...‘ % n) time.sleep(1) r = ‘200 OK‘def produce(c): # 1、首先調用c.next()啟動產生器 next(c) n = 0 while n < 5: n = n + 1 print(‘[PRODUCER] →→ Producing %s...‘ % n) # 2、然後,一旦生產了東西,通過c.send(n)切換到consumer執行; cr = c.send(n) # 4、produce拿到consumer處理的結果,繼續生產下一條訊息; print(‘[PRODUCER] Consumer return: %s‘ % cr) # 5、produce決定不生產了,通過c.close()關閉consumer,整個過程結束。 c.close()if __name__==‘__main__‘: # 6、整個流程無鎖,由一個線程執行,produce和consumer協作完成任務,所以稱為“協程”,而非線程的搶佔式多任務。 c = consumer() produce(c)
greenlet模組
可以實現手動切換
調用屬性swich
gevent可以實現IO的監聽
gevent.joinall 開啟所有程式
gevent.spawn 切換
3 IO模型
IO指input, output
IO發生時涉及的對象和步驟
會涉及到兩個系統對象,一個是調用這個IO的process(or thread),另一個就是系統核心(kernel)。當一個操作發生時,會經曆兩個階段:
(1) 等待資料準備
(2) 將資料從核心拷貝到進程中
IO模型類型:
- 1. 阻塞 IO
- 1. 非阻塞 IO
非阻塞IO:發送多次系統調用
優點:wait for data無阻塞
缺點:系統調用太多
不能及時拿到資料
兩個階段:wait for data非阻塞
copy data 阻塞
非阻塞的recvform系統調用調用之後,進程並沒有被阻塞,核心馬上返回給進程,如果資料還沒準備好,此時會返回一個error。進程在返回之後,可以幹點別的事情,然後再發起recvform系統調用。重複上面的過程,迴圈往複的進行recvform系統調用。這個過程通常被稱之為輪詢。輪詢檢查核心資料,直到資料準備好,再拷貝資料到進程,進行資料處理。需要注意,拷貝資料整個過程,進程仍然是屬於阻塞的狀態。
- 1. IO多工(監聽多個連結)
特點:(1)全程阻塞
能監聽多個檔案描述符 實現並發
#服務端import selectimport socketsock=socket.socket()#產生一個通訊端sock.bind(("127.0.0.1",8080))sock.listen(5)sock.setblocking(False)inputs=[sock,]while 1: r,w,e=select.select(inputs,[],[])#監聽有變化的通訊端sock #wait for data for obj in r: if obj==sock: conn,addr=obj.accept()#從核心copy資訊到使用者態 print("conn",conn) inputs.append(conn)#監聽列表添加客戶conn else: data=obj.recv(1024)#接收資訊 print(data.decode("utf8")) send_data=input(">>")#發送資訊 obj.send(send_data.encode("utf8"))#用戶端import socketsock=socket.socket()sock.connect(("127.0.0.1",8080))while 1: data=input("input>>") sock.send(data.encode("utf8")) recv_data=sock.recv(1024) print(recv_data.decode("utf8")) sock.close()
對於檔案描述符(通訊端對象)
(1) 是一個非零整數,不會變
(2) 收發資料的時候,對於接收端而言,資料先到核心空間,然後copy到使用者空間,同時,核心空間資料清除
- 1. 非同步IO
全程無阻塞
5.驅動訊號
小結:
有阻塞blocking
無阻塞non-blocking
調用blocking IO會一直block住對應的進程知道操作完成
non-blocking IO在kernel還準備資料的情況下會立刻返回
有阻塞是同步阻塞:阻塞 非阻塞 IO多工
無阻塞是非同步阻塞:非同步IO
4 selectors模組
IO多工實現機制
Win:select
Linux:select,poll,epoll
Select缺點:1.每次調用select都要將所有的fd(檔案描述符)拷貝到核心空間,導致效率下降
2.遍曆所有的fd,是否有資料訪問(最重要的問題)
3.最大串連數(1024)
poll:最大串連數沒有限制
epoll:1.第一個函數建立epoll控制代碼,將所有的fd(檔案描述符)拷貝到核心空間
只需要拷貝一次
2.回呼函數:某一個函數或者某一個動作成功完成之後會觸發的函數
為所有的fd綁定一個回呼函數,但有資料訪問觸發該回呼函數
回呼函數將fd放到列表中
import selectorsimport socketsock=socket.socket()sock.bind(("127.0.0.1",8080))sock.listen(5)sock.setblocking(False)sel=selectors.DefaultSelector()#根據具體平台選擇最佳IO多路機制def read(conn,mask): try: data=conn.recv(1024) print(data.decode("utf8")) data2=input(">>") conn.send(data2.encode("utf8")) except Exception: sel.unregister(conn)def accept(sock,mask): sel.register(sock,selectors.EVENT_READ,accept) conn,addr=sock.accept() sel.register(conn,selectors.EVENT_READ,read)sel.register(sock,selectors.EVENT_READ,accept)#註冊功能while 1: events=sel.select() for key,mask in events: print(key.data)#定義的函數 print(key.fileobj)#socket對象 func=key.data obj=key.fileobj func(obj,mask)breakimport socketsock=socket.socket()sock.connect(("127.0.0.1",8080))while 1: data=input("input>>") sock.send(data.encode("utf8")) recv_data=sock.recv(1024) print(recv_data.decode("utf8"))sock.close()
5. 隊列
隊列用在多線程,多進程中,用來保護資料
隊列是個資料類型
優點:安全執行緒
import queueq=queue.Queue(3)#預設是先進先出q.put(111)q.put("hello")q.put(222)print(q.get())print(q.get())print(q.get())>>111hello222import queueq=queue.Queue(3)#預設是先進先出q.put(111)q.put("hello")q.put(222)q.put(223,False)#q=queue.Queue(3)隊列定義只能放3個值,# #超過限額時,返回錯誤資訊print(q.get())print(q.get())print(q.get())q.get()#沒有資料的時候不會報錯,只會等待q.get(False)#資料為空白,報錯先進後出import queueq=queue.LifoQueue()q.put(111)q.put(5)q.put(43)print(q.get())優先順序import queueq=queue.PriorityQueue()q.put([4,"hello"])q.put([1,"hello5"])print(q.get())
python\進程和線程3