線程進階
阿新 • • 發佈:2018-02-02
bind 有一個 參數 conn 函數依賴 __name__ enc pos 釋放
在了解進程之後,我們可以做一個多線程的聊天室
服務端
import socket from multiprocessing import Process def talk(conn): conn.send(b‘connected‘) ret = conn.recv(1024) print(ret) if __name__ == ‘__main__‘: sk = socket.socket() sk.bind((‘127.0.0.1‘, 8080)) sk.listen() while True: conn,addr = sk.accept() p= Process(target=talk,args=(conn,)) p.start() conn.close() sk.close()
客戶端
import socket sk = socket.socket() sk.connect((‘127.0.0.1‘,8080)) ret = sk.recv(1024) print(ret) msg = input(‘>>>‘) sk.send(msg.encode(‘utf-8‘)) sk.close()
我們不論建立幾個客戶端都可以做到和服務端互動,他們每一個都是自己獨立的線程
守護進程 子進程會在主進程結束時結束
# start 開啟一個進程 # join 用join可以讓主進程等待子進程結束 # 守護進程 # 守護進程會隨著主進程的代碼執行結束而結束 # 正常的子進程沒有執行完的時候主進程要一直等著 import time from multiprocessing import Process def func(): print(‘--‘*10) time.sleep(15) print(‘--‘*10) def cal_time(): while True: time.sleep(1) print(‘過去了1秒‘) if __name__== ‘__main__‘: p = Process(target=cal_time) p.daemon = True # 一定在開啟進程之前設置 p.start() p2 = Process(target=func) # 15s p2.start() for i in range(100): # 10s time.sleep(0.1) print(‘*‘*i) p2.join() # 守護進程的進程的作用: # 會隨著主進程的代碼執行結束而結束,不會等待其他子進程 # 守護進程 要在start之前設置 # 守護進程中 不能再開啟子進程
進程的其他方法
import time from multiprocessing import Process # def func(): # print(‘wahaha‘) # time.sleep(5) # print(‘qqxing‘) # if __name__ == ‘__main__‘: # p = Process(target=func) # p.start() # print(p.is_alive()) # # time.sleep(0.1) # p.terminate() # 關閉進程 異步 # print(p.is_alive()) # ??? # time.sleep(1) # print(p.is_alive()) # p.is_alive() # 是否活著 True代表進程還在 False代表進程不在了 # p.terminate() # 結束一個進程,但是這個進程不會立刻被殺死 # 屬性 # pid 查看這個進程 進程id # name 查看這個進程的名字 # def func(): # print(‘wahaha‘) # time.sleep(5) # print(‘qqxing‘) # if __name__ == ‘__main__‘: # p = Process(target=func) # p.start() # print(p.name,p.pid) # p.name = ‘哇哈哈哈‘ # print(p.name) # class MyProcess(Process): # def run(self): # print(‘wahaha‘,self.name,self.pid) # time.sleep(5) # print(‘qqxing‘,self.name,self.pid) # if __name__ == ‘__main__‘: # p = MyProcess() # p.start() # print(p.pid) # 進程中的其他方法 # 守護進程 p.daemon = True # 兩個方法 p.is_alive() p.terminate() # 兩個屬性 p.pid p.name
鎖 在一個主線程開啟多個子線程時,這幾個子線程的數據是隔離的,但是當他們都與主進程互動時,難免會產生數據混亂,這種情況我們叫做
數據不安全,解決辦法就是在進程中加鎖
# from multiprocessing import Lock # lock = Lock() # lock.acquire() # 需要鎖 拿鑰匙 # lock.acquire() # 需要鎖 阻塞 # # lock.release() # 釋放鎖 還鑰匙 # 鎖 就是在並發編程中 保證數據安全 # 多進程 實現 並發 import json import time import random from multiprocessing import Lock from multiprocessing import Process def search(i): with open(‘ticket‘) as f: print(i,json.load(f)[‘count‘]) def get(i): with open(‘ticket‘) as f: ticket_num = json.load(f)[‘count‘] time.sleep(random.random()) if ticket_num > 0: with open(‘ticket‘,‘w‘) as f: json.dump({‘count‘:ticket_num-1},f) print(‘%s買到票了‘%i) else: print(‘%s沒票了‘%i) def task(i,lock): search(i) # 查看票 lock.acquire() get(i) # 搶票 lock.release() if __name__ == ‘__main__‘: lock = Lock() for i in range(20): # 20個人同時搶票 p = Process(target=task,args=(i,lock)) p.start()
當我們需要同時幾個進程的時候,就相當於多給幾個鑰匙,這種情況叫信號量
# 信號量 from multiprocessing import Semaphore # sem = Semaphore(4) # sem.acquire() # 需要鑰匙 # print(0) # sem.acquire() # 需要鑰匙 # print(1) # sem.acquire() # 需要鑰匙 # print(2) # sem.acquire() # 需要鑰匙 # print(3) # sem.release() # sem.acquire() # 需要鑰匙 # print(4) import time import random from multiprocessing import Semaphore from multiprocessing import Process def sing(i,sem): sem.acquire() print(‘%s : 進入 ktv‘%i) time.sleep(random.randint(1,10)) print(‘%s : 出 ktv‘%i) sem.release() # 迷你唱吧 20個人,同一時間只能有4個人進去唱歌 if __name__ == ‘__main__‘: sem = Semaphore(4) for i in range(20): Process(target=sing,args=(i,sem)).start()
event模塊
可以控制進程的阻塞
# 事件 # 所有的阻塞 都是同步 # recv accept input sleep # 阻塞多個進程 異步阻塞 # lock 10進程 # 事件 —— 異步阻塞 # 事件 標誌 同時 是所有的進程 都陷入阻塞 from multiprocessing import Event #事件 # e = Event() # 實例化一個事件 標誌/交通信號燈 # e.set() # 將標誌變成非阻塞/交通燈變綠 # e.wait() # 剛實例化出來的一個事件對象,默認的信號是阻塞信號/默認是紅燈 # # 執行到wait,要先看燈,綠燈行紅燈停,如果在停的過程中燈綠了, # # 就變成非阻塞了 # e.clear() # 將標誌又變成阻塞/交通燈變紅 # # e.is_set() # 是否阻塞 True就是綠燈 False就是紅燈 # 紅綠燈 import time import random from multiprocessing import Process from multiprocessing import Event def traffic_light(e): while True: if e.is_set(): time.sleep(3) print(‘紅燈亮‘) e.clear() # 綠變紅 else: time.sleep(3) print(‘綠燈亮‘) e.set() # 紅變綠 def car(i,e): e.wait() print(‘%s車通過‘%i) if __name__ == ‘__main__‘: e = Event() # 立一個紅燈 tra = Process(target=traffic_light,args=(e,)) tra.start() # 啟動一個進程來控制紅綠燈 for i in range(100): if i%6 == 0 : time.sleep(random.randint(1,3)) car_pro = Process(target=car, args=(i,e)) car_pro.start()
當我們想要在幾個子進程間調用數據時,使用隊列方法
# 進程之間的通信 # lock # 1 lock.acquire # 2 lock.acquire # sem # e # ‘hello‘ --> 子進程 # 子進程1 ‘hello’ --> 子進程2 from multiprocessing import Queue # q = Queue(3) # q.put(1) # q.put(2) # q.put(3) # q.put(4) # # print(q.get()) # print(q.get()) # print(q.get()) # print(q.get()) # 如果隊列裏已經沒有值了 就會阻塞等待有一個值 #1.進程之間通信 可以使用multiprocessing 的 Queue模塊 #2.隊列有兩種創建方式 第一種不傳參數 這個隊列就沒有長度限制 ;傳參數,創建一個有最大長度限制的隊列 #3.提供兩個重要方法;put get #4.qsize from multiprocessing import Process from multiprocessing import Queue # def q_put(q): # q.put(‘hello‘) # # def q_get(q): # print(q.get()) # # if __name__ ==‘__main__‘: # q = Queue() # p = Process(target=q_put,args=(q,)) # p.start() # p1 = Process(target=q_get, args=(q,)) # p1.start() # 通過隊列實現了 主進程與子進程的通信 子進程與子進程之間的通信 # 生產者消費者模型 # 我要生產一個數據 然後 給一個函數 讓這個函數依賴這個數據進行運算 拿到結果 —— 同步過程 # 做包子 和 吃包子 import time def producer(q): # 生產者 for i in range(100): q.put(‘包子%s‘%i) def consumer(q): # 消費者 for i in range(100): time.sleep(1) print(q.get()) if __name__ == ‘__main__‘: q = Queue(10) # 托盤 p = Process(target=producer,args=(q,)) p.start() c1 = Process(target=consumer, args=(q,)) c2 = Process(target=consumer, args=(q,)) c1.start() c2.start() # 首先 對於內存空間來說 每次只有很少的數據會在內存中 # 對於生產與消費之間的不平衡來說 # 增加消費者或者增加生產者來調節效率
線程進階