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

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