python中并发编程基础1
并發編程基礎概念
1.進程。
什么是進程?
正在運行的程序就是進程。程序只是代碼。
什么是多道?
多道技術:
1.空間上的復用(內存)。將內存分為幾個部分,每個部分放入一個程序,這樣同一時間在內存中就有了多道程序。
2.時間上的復用(CPU的分配)。只有一個CPU,如果程序在運行過程中遇到了I/O阻塞或者運行時間足夠長。操作系統會按照算法將CPU分配給其他程序使用,依次類推。直到第一個程序被重新分配到CPU會繼續運行。
多道技術中的問題解決:
空間復用:程序之間的內存必須分割。這種分割需要在硬件層面實現,由操作系統控制。保證安全性和穩定性。
multiprocessing模塊的使用
python中的多線程無法利用多核優勢,如果想要充分地使用多核CPU的資源,python中大部分情況需要使用多進程。python提供了multiprocessing模塊。
multiprocessing模塊是用來開啟子進程,并可以在子進程中定制任務。
Process類
process類的作用是用來創建進程的類。
Process([group [, target [, name [, args [, kwargs]]]]]),由該類實例化得到的對象,表示一個子進程中的任務(尚未啟動)
強調:
需要使用關鍵字的方式來指定參數
args指定的為傳給target函數的位置參數,是一個元組形式,必須有逗號
參數介紹:
1、group參數未使用,值始終為None
2、target表示調用對象,即子進程要執行的任務
3、args表示調用對象的位置參數元組,args=(1,2,'ming',)
4、kwargs表示調用對象的字典,kwargs={'name':'ming','age':20}
5、name為子進程的名稱
?
**方法介紹**:?
1、p.start():啟動進程,并調用該子進程中的p.run()
?
2、p.run():進程啟動時運行的方法,正是它去調用target指定的函數,我們自定義類的類中一定要實現該方法 ?
?
3、p.terminate():強制終止進程p,不會進行任何清理操作,如果p創建了子進程,該子進程就成了僵尸進程,使用該方法需要特別小心這種情況。如果p還保存了一個鎖那么也將不會被釋放,進而導致死鎖
?
4、p.is_alive():如果p仍然運行,返回True
?
5、p.join([timeout]):主線程等待p終止(強調:是主線程處于等的狀態,而p是處于運行的狀態)。timeout是可選的超時時間,需要強調的是,p.join只能join住start開啟的進程,而不能join住run開啟的進程
?
**屬性介紹:**?
1、p.daemon:默認值為False,如果設為True,代表p為后臺運行的守護進程,當p的父進程終止時,p也隨之終止,并且設定為True后,p不能創建自己的新進程,必須在p.start()之前設置
?
2、p.name:進程的名稱
?
3、p.pid:進程的pid
?
4、p.exitcode:進程在運行時為None、如果為–N,表示被信號N結束(了解即可)
5、p.authkey:進程的身份驗證鍵,默認是由os.urandom()隨機生成的32字符的字符串。這個鍵的用途是為涉及網絡連接的底層進程間通信提供安全性,這類連接只有在具有相同的身份驗證鍵時才能成功(了解即可)
?
?? 5.Process類的使用
? #創建進程的第一種方式##注意:在windows 中,開啟一個子進程就是完全復制一個父進程的代碼并運行。如果不寫在if __name__ == '__main__':下面會形成一個無窮的循環。if __name__ == '__main__':的作用是以當前文件運行__name__ 會== '__main__'from multiprocessing import Processimport osdef task():print('task run')print('子進程task', os.getpid())print('子進程task父進程', os.getppid())if __name__ == '__main__':#創建子進程p = Processp = Process(target=task, name= '這是子進程')p.start() # 給操作系統發送通知 要求操作系統開啟進程,會自動調用run()方法print('py文件進程', os.getpid())print('py文件進程的父進程', os.getppid())###輸出結果py文件進程 10532py文件進程的父進程 15348 task run子進程task 4356子進程task父進程 10532?
? #開啟進程的第二種方式#創建一個類,該類繼承Process類,覆蓋Process中的run方法,其優勢是 可以自定義 進程的屬性和行為 來完成一些額外任務 例如下載from multiprocessing import Processimport osclass MyProcess(Process):def __init__(self, url):self.url = urlsuper().__init__()def run(self): #方法名必須是runprint('下載文件。。。。', self.url)print('子進程run的進程ID', os.getpid())print('子進程run的父進程ID', os.getppid())if __name__ == '__main__':p = MyProcess('21215135') p.start() #會自動執行runprint('py文件的進程ID', os.getpid())print('py文件的父進程ID', os.getppid())?
進程之間的內存空間是隔離的
from multiprocessing import Process import time ? a = 1002020212 ? def test():global aa = 33520print('test進程的a', a) ? if __name__ == '__main__':p = Process(target=test) #創建進程p.start() #啟動進程 ?time.sleep(1)print('py文件進程中的a', a)###輸出結果 test進程的a 33520 py文件進程中的a 1002020212 結論: 1.子進程中的數據修改,不會影響父進程。 2.子進程的創建和父進程無關。?
Process對象的join方法
join方法的作用是:父進程等待子進程結束。
from multiprocessing import Process import time ? def task(num):# time.sleep(2)print('我是%s號進程' % num) ? if __name__ == '__main__':start_time = time.time()ps = []for i in range(5):s = Process(target=task, args=(i,))s.start()ps.append(s)for n in ps:n.join(0.04)print(time.time()-start_time)print('over')?
Process對象常用屬性
from multiprocessing import Process import time ? def test():time.sleep(3)print('life is so short, i use python') ? if __name__ == '__main__':p = Process(target=test, name='daidai')p.start()print(p.name) #進程名print(p.is_alive()) #進程是否存活# p.terminate() #終止進程print(p.pid) ### daidaiTrue20108life is so short, i use python?
孤兒進程和僵尸進程
孤兒進程:是指父進程已經終止,但是自己還在運行
??? 孤兒進程是無害的:例如QQ打開了瀏覽器, 然后QQ關閉,瀏覽器運行
僵尸進程:是指子進程完全執行完所有的任務,已經終止了但是還殘留一些信息。(進程id 和 進程名等)
??? 但是父進程沒有處理這些殘留信息,導致殘留信息占用系統內存。
當出現大量的僵尸進程時,會占用系統資源,可以將他的父進程殺掉,僵尸成了孤兒,然后操作系統會負責收回內存。
##基于多進程實現并發通信服務器from socket import * from multiprocessing import Process import structserver = socket() server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) server.bind(('127.0.0.1', 33520)) server.listen() def communicate(c, addr):try:while True:data = c.recv(4) #1msg_len = struct.unpack('i', data)[0]msg_data = c.recv(msg_len) #2if not msg_data:err_info = '對方正在輸入!'err_info_data = err_info.encode('utf-8')back_len_data = struct.pack('i', len(err_info_data))c.send(back_len_data)c.send(err_info_data)back_len = struct.pack('i', len(msg_data))c.send(back_len)c.send(msg_data)print(msg_data.decode('utf-8'))except Exception as e:print(e)if __name__ == '__main__':while True:c, addr = server.accept()p = Process(target=communicate, name=None, args=(c, addr))p.start()#客戶端,可開啟多個,但是每連接一個就開啟一個進程 from socket import * import structclient = socket() client.connect(('127.0.0.1', 33520)) while True:msg = input('請輸入發送的消息:').strip()msg_data = msg.encode('utf-8')msg_len_s = struct.pack('i', len(msg_data))client.send(msg_len_s)client.send(msg_data)data_len = client.recv(4) #收到消息長度length = struct.unpack('i', data_len)[0]data = client.recv(length)back_msg = data.decode('utf-8')print('返回的消息:%s' % back_msg)
?
轉載于:https://www.cnblogs.com/5j421/p/10192293.html
總結
以上是生活随笔為你收集整理的python中并发编程基础1的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++实现平衡二叉树
- 下一篇: [BZOJ3595][SCOI2014]