目錄
- 一、multiprocess模塊
- 二、multiprocess.process模塊
-
三、Process類
- 3.1 方法介紹
- 3.2 屬性介紹
- 3.3 在windows中使用Process類的注意事項
-
四、process類的使用
- 4.1 創(chuàng)建并開啟子進(jìn)程的兩種方式
- 4.2 join方法
- 4.3 查看主進(jìn)程和子進(jìn)程的進(jìn)程號
- 4.4 查看進(jìn)程名和進(jìn)程狀態(tài)、設(shè)置進(jìn)程名
- 4.5 terminate結(jié)束子進(jìn)程
- 4.6 Process中的守護(hù)進(jìn)程
-
五、socket聊天并發(fā)實例
- 5.1 使用多進(jìn)程實現(xiàn)socket聊天并發(fā)-server端
- 5.2 使用多進(jìn)程實現(xiàn)socket聊天并發(fā)-client端
運行中的程序就是一個進(jìn)程。 所有的進(jìn)程都是通過它的父進(jìn)程來創(chuàng)建的 。因此,運行起來的python程序也是一個進(jìn)程,那么我們也可以在程序中再創(chuàng)建進(jìn)程。多個進(jìn)程可以實現(xiàn)并發(fā)效果,當(dāng)我們的程序中存在多個進(jìn)程的時候,在某些時候,就會讓程序的執(zhí)行速度變快。
在linux c語言中創(chuàng)建線程使用的fork函數(shù),而Python就需要借助響應(yīng)的模塊
一、multiprocess模塊
仔細(xì)說來,multiprocess不是一個模塊而是python中一個操作、管理進(jìn)程的包。 之所以叫multi是取自multiple的多功能的意思,在這個包中幾乎包含了和進(jìn)程有關(guān)的所有子模塊。由于提供的子模塊非常多,為了方便大家歸類記憶,我將這部分大致分為四個部分:創(chuàng)建進(jìn)程部分,進(jìn)程同步部分,進(jìn)程池部分,進(jìn)程之間數(shù)據(jù)共享。
二、multiprocess.process模塊
process模塊是一個創(chuàng)建進(jìn)程的模塊,借助這個模塊,就可以完成進(jìn)程的創(chuàng)建。
三、Process類
Process([group [, target [, name [, args [, kwargs]]]]])
,由該類實例化得到的對象,表示一個子進(jìn)程中的任務(wù)(尚未啟動)
強調(diào):
- 需要使用關(guān)鍵字的方式來指定參數(shù)
- args指定的為傳給target函數(shù)的位置參數(shù),是一個元組形式,必須有逗號
參數(shù)介紹:
- group參數(shù)未使用,值始終為None
- target表示調(diào)用對象,即子進(jìn)程要執(zhí)行的任務(wù)
-
args表示調(diào)用對象的位置參數(shù)元組,
args=(1,2,'egon',)
-
kwargs表示調(diào)用對象的字典,
kwargs={'name':'egon','age':18}
- name為子進(jìn)程的名稱
3.1 方法介紹
-
p.start()
:啟動進(jìn)程,并調(diào)用該子進(jìn)程中的p.run() -
p.run()
:進(jìn)程啟動時運行的方法,正是它去調(diào)用target指定的函數(shù),我們自定義類的類中一定要實現(xiàn)該方法 -
p.terminate()
:強制終止進(jìn)程p,不會進(jìn)行任何清理操作,如果p創(chuàng)建了子進(jìn)程,該子進(jìn)程就成了僵尸進(jìn)程,使用該方法需要特別小心這種情況。如果p還保存了一個鎖那么也將不會被釋放,進(jìn)而導(dǎo)致死鎖 -
p.is_alive()
:如果p仍然運行,返回True -
p.join([timeout])
:主線程等待p終止(強調(diào):是主線程處于等的狀態(tài),而p是處于運行的狀態(tài))。timeout是可選的超時時間,需要強調(diào)的是,p.join只能join住start開啟的進(jìn)程,而不能join住run開啟的進(jìn)程
3.2 屬性介紹
-
p.daemon
:默認(rèn)值為False,如果設(shè)為True,代表p為后臺運行的守護(hù)進(jìn)程,當(dāng)p的父進(jìn)程終止時,p也隨之終止,并且設(shè)定為True后,p不能創(chuàng)建自己的新進(jìn)程,必須在p.start()
之前設(shè)置 -
p.name
:進(jìn)程的名稱 -
p.pid
:進(jìn)程的pid -
p.exitcode
:進(jìn)程在運行時為None、如果為–N,表示被信號N結(jié)束(了解即可) -
p.authkey
:進(jìn)程的身份驗證鍵,默認(rèn)是由os.urandom()
隨機生成的32字符的字符串。這個鍵的用途是為涉及網(wǎng)絡(luò)連接的底層進(jìn)程間通信提供安全性,這類連接只有在具有相同的身份驗證鍵時才能成功(了解即可)
3.3 在windows中使用Process類的注意事項
在Windows操作系統(tǒng)中由于沒有fork(linux操作系統(tǒng)中創(chuàng)建進(jìn)程的機制),在創(chuàng)建子進(jìn)程的時候會自動 import 啟動它的這個文件,而在 import 的時候又執(zhí)行了整個文件。因此如果將process()直接寫在文件中就會無限遞歸創(chuàng)建子進(jìn)程報錯。所以必須把創(chuàng)建子進(jìn)程的部分使用
if __name__ =='__main__'
判斷保護(hù)起來,import 的時候,就不會遞歸運行了。
四、process類的使用
在一個python進(jìn)程中開啟子進(jìn)程,start方法和并發(fā)效果。
4.1 創(chuàng)建并開啟子進(jìn)程的兩種方式
-
方式一:通過函數(shù)
from multiprocessing import Process import time ''' 開啟子進(jìn)程的兩種方式: 1. 通過函數(shù) 2. 通過類。繼承Process ''' def task(name): print("進(jìn)程{%s} start"%(name)) time.sleep(2) print(f"進(jìn)程{name} end") # 必須加main if __name__ == '__main__': ######## 方式1(通過函數(shù)) p = Process(target=task,args=("xc",)) # args用于傳參,是個元祖,必須加逗號 p.start() # 告訴操作系統(tǒng)啟動子進(jìn)程,但一定是父進(jìn)程先執(zhí)行,多個子進(jìn)程的執(zhí)行順序是根據(jù)操作系統(tǒng)調(diào)度決定的 print('主進(jìn)程/父進(jìn)程') print('主進(jìn)程/父進(jìn)程') p1 = Process(target=task,args=("cyx",)) p1.start() # 告訴操作系統(tǒng)啟動子進(jìn)程,但一定是父進(jìn)程先執(zhí)行,多個子進(jìn)程的執(zhí)行順序是根據(jù)操作系統(tǒng)調(diào)度決定的 print('主進(jìn)程/父進(jìn)程') print('主進(jìn)程/父進(jìn)程') print('主進(jìn)程/父進(jìn)程') print('主進(jìn)程/父進(jìn)程')
-
方式二:通過類。繼承Process
from multiprocessing import Process import time ''' 開啟子進(jìn)程的兩種方式: 1. 通過函數(shù) 2. 通過類。繼承Process ''' class myProcess(Process): def __init__(self,name): # self.name = name #錯誤 ### 這樣沒有給對象添加屬性name,而是在修改父類的進(jìn)程名(name) # 父類Process的進(jìn)程名也是name super().__init__() # 調(diào)用父類super().init方法完成創(chuàng)建進(jìn)程初始化,重新給name屬性賦值了。 self.name = name ## 在父類的init方法后設(shè)置name,才是為自己對象添加屬性 # super().__init__(name=name) # 調(diào)用父類super().init,并設(shè)置進(jìn)程名(name) def run(self): # 創(chuàng)建進(jìn)程會默認(rèn)調(diào)用run方法 print("進(jìn)程%s start" % (self.name)) time.sleep(2) print(f"進(jìn)程{self.name} end") # 必須加main if __name__ == '__main__': p = myProcess("xc") p.start() print('主進(jìn)程/父進(jìn)程') print('主進(jìn)程/父進(jìn)程') p1 = myProcess("cyx") p1.start() # 告訴操作系統(tǒng)啟動子進(jìn)程,但一定是父進(jìn)程先執(zhí)行,多個子進(jìn)程的執(zhí)行順序是根據(jù)操作系統(tǒng)調(diào)度決定的 print('主進(jìn)程/父進(jìn)程') print('主進(jìn)程/父進(jìn)程') print('主進(jìn)程/父進(jìn)程') print('主進(jìn)程/父進(jìn)程')
4.2 join方法
join方法用于回收子進(jìn)程
from multiprocessing import Process
import time
def foo(x):
print('進(jìn)程 start ')
time.sleep(x)
print('進(jìn)程 end ')
if __name__ == '__main__':
### 串行執(zhí)行和回收子進(jìn)程
# p = Process(target=foo, args=(1,))
# p2 = Process(target=foo, args=(2,))
# p3 = Process(target=foo, args=(3,))
# p.start() #
# p.join() # 阻塞住主進(jìn)程再等待子進(jìn)程結(jié)束,然后再往下執(zhí)行,(了解的是:內(nèi)部會待用wait())
# p2.start()
# p2.join()
# p3.start()
# p3.join()
# print('主')
# 并發(fā)執(zhí)行進(jìn)程,并依次回收
p = Process(target=foo, args=(1,))
p2 = Process(target=foo, args=(2,))
p3 = Process(target=foo, args=(3,))
# 開啟進(jìn)程
p.start()
p2.start()
p3.start()
# 回收進(jìn)程
p.join() # 阻塞住主進(jìn)程再等待子進(jìn)程結(jié)束,然后再往下執(zhí)行,(了解的是:內(nèi)部會待用wait())
p2.join()
p3.join()
print('主')
4.3 查看主進(jìn)程和子進(jìn)程的進(jìn)程號
from multiprocessing import Process,current_process
import time
import os
'''
查看主進(jìn)程和子進(jìn)程的進(jìn)程號
1. 通過os.getpid()方法
2. 通過multiprocessing模塊中的current_process().pid
'''
def task(name,x):
print("當(dāng)前進(jìn)程pid:", current_process().pid)
print(f"{name} start")
time.sleep(x)
print(f"{name} end")
if __name__ == '__main__':
p = Process(target=task,args=("進(jìn)程1",1))
p.start()
# 方式一
print("子進(jìn)程pid:",p.pid)
# 方式二
# print("當(dāng)前進(jìn)程pid:",current_process().pid)
print("當(dāng)前進(jìn)程pid",os.getpid())
print("主進(jìn)程的父進(jìn)程pid",os.getppid()) # 實際上是pycharm的進(jìn)程號
print()
4.4 查看進(jìn)程名和進(jìn)程狀態(tài)、設(shè)置進(jìn)程名
'''
process設(shè)置名字: name屬性
process判斷進(jìn)程是否存在:is_alive
'''
from multiprocessing import Process
import time
def task(x):
print("進(jìn)程 start")
time.sleep(x)
print("進(jìn)程 end")
if __name__ == '__main__':
p = Process(target=task,args=(1,))
p.start()
p.name = "進(jìn)程1"
print(p.name)
print("子進(jìn)程是否存在:", p.is_alive()) # True
time.sleep(2) # 延時2秒等待子進(jìn)程結(jié)束
print("子進(jìn)程是否存在:", p.is_alive()) # False
print("主進(jìn)程")
4.5 terminate結(jié)束子進(jìn)程
'''
terminate()
告訴子進(jìn)程讓他結(jié)束
'''
from multiprocessing import Process
import time
def task(x):
print("進(jìn)程 start")
time.sleep(x)
print("進(jìn)程 end")
if __name__ == '__main__':
p = Process(target=task,args=(10,))
p.start()
p.terminate() # 告訴子進(jìn)程讓他提前結(jié)束
p.name = "進(jìn)程1"
print(p.name)
print("子進(jìn)程是否存在:", p.is_alive()) # True
p.join()
print("子進(jìn)程是否存在:", p.is_alive()) # False
print("主進(jìn)程")
4.6 Process中的守護(hù)進(jìn)程
首先,博主自己測試,實驗。Process中守護(hù)進(jìn)程的部分和真正的守護(hù)進(jìn)程概念并不一樣,因此只需要知道Process的守護(hù)進(jìn)程即可。
'''
daemon = True 把子進(jìn)程變?yōu)槭刈o(hù)進(jìn)程
主進(jìn)程的代碼執(zhí)行完畢守護(hù)進(jìn)程直接結(jié)束。但如果子進(jìn)程代碼結(jié)束也會結(jié)束
'''
from multiprocessing import Process
import time
def task(x):
print("進(jìn)程 start")
time.sleep(x)
print("進(jìn)程 end")
if __name__ == '__main__':
p = Process(target=task,args=(2,))
p.daemon = True # 把子進(jìn)程變?yōu)槭刈o(hù)進(jìn)程
p.start()
# print(p.pid)
p.name = "進(jìn)程1"
print(p.name)
print("子進(jìn)程pid:", p.pid) #
print("子進(jìn)程是否存在:", p.is_alive()) # True
time.sleep(3)
print("子進(jìn)程是否存在:", p.is_alive()) # False
print("主進(jìn)程")
print("子進(jìn)程是否存在:", p.is_alive()) # False
time.sleep(200)
五、socket聊天并發(fā)實例
5.1 使用多進(jìn)程實現(xiàn)socket聊天并發(fā)-server端
import socket
from multiprocessing import Process
def talk(conn,client_addr):
while 1:
msg = conn.recv(1024)
if not msg:
break
print(msg.decode("utf8"))
conn.send(msg.upper())
print(111)
if __name__ == '__main__':
# 必須要寫在里面,不然會因為創(chuàng)建子線程重復(fù)調(diào)用導(dǎo)致端口被占用
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("127.0.0.1", 8087))
server.listen(5)
while 1:
print("等待連接")
conn,addr = server.accept()
print(addr,"連接成功")
p = Process(target=talk,args=(conn,addr))
p.start()
5.2 使用多進(jìn)程實現(xiàn)socket聊天并發(fā)-client端
import socket
if __name__ == '__main__':
client = socket.socket()
client.connect(("127.0.0.1",8087))
while 1:
msg = input("請輸入內(nèi)容")
client.send(msg.encode("utf8"))
msg = client.recv(1024).decode("utf8")
print(msg)
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
