Python網路編程——進程
TechBoard / techLee
***
微信公眾號:TechBoard
***
##### 進程
> 進程:通俗理解就是一個運行的程序或者軟體,進程是操作系統資源分配的基本單位
> 一個程序至少有一個進程,一個進程至少有一個線程,多進程可以完成多任務
##### 進程的狀態
> 工作中,任務數往往大於cpu的核數,即一定有一些任務正在執行,而另外一些任務在等待cpu進行執行,因此導致了有了不同的狀態
##### 進程的使用
> 導入進程模塊:
```
import multiprocessing
```
> 用進程完成多任務
```
import multiprocessing
import time
def sing():
for i in range(10):
print("唱歌中...")
time.sleep(0.2)
def dance():
for i in range(10):
print("跳舞中...")
time.sleep(0.2)
if __name__ == "__main__":
# 創建對應的子進程執行對應的任務
sing_process = multiprocessing.Process(target=sing)
dance_process = multiprocessing.Process(target=dance)
# 啟動進程執行對應的任務
sing_process.start()
dance_process.start()
```
##### Process類參數介紹
```
import multiprocessing
import os
def show_info(name,age):
print("show_info:", multiprocessing.current_process())
# 獲取進程的編號
pritn("show_info pid:", multiprocessing.current_process().pid, os.getpid)
print(name, age)
if __name__ == "__main__":
# 創建子進程
# group: 進程組,目前只能使用None
# target: 執行的目標任務
# args: 以元組方式傳參
# kwargs: 以字典方式傳參
sub_prcess = multiprocessing.Process(group=None, target=show_info, arg=("楊冪", 18))
sub_prcess.start()
```
##### 進程之間不共享全局變數
```
import multiprocessing
import time
# 全局變數
g_list = []
# 添加數據
def add_data():
for i in range(15):
g_list.append(i)
time.sleep(0.1)
print("add_data:", g_list)
# 讀取數據
def read_data():
print("read_data:", g_list)
if __name__ == "__main__":
# 創建添加數據的子進程
add_process = multiprocessing.Process(target=add_data)
# 創建讀取數據的子進程
read_process = multiprocessing.Process(target=read_data)
# 啟動進程
add_process.start()
# 主進程等待添加數據的子進程執行完成以後再執行讀取進程的操作
add_process.join()
# 代碼執行到此說明添加數據的子進程把任務執行完成了
read_process.start()
```
> 創建子進程其實就是對主進程資源的拷貝
> 主進程會等待所有的子進程執行完成程序再退出
```
import multiprocessing
import time
# 工作任務
def work():
for i in range(10):
print("工作中...")
time.sleep(0.3)
if __name__ == "__main__":
# 創建子進程
sub_prcess = multiprocessing.Process(target=work)
# 查看進程的守護狀態
# print(sub_prcess.daemon)
# 守護主進程,主進程退出子進程直接銷毀,不再執行子進程裡面的代碼
# sub_prcess.daemon = True
# 啟動進程執行對應的任務
sub_process.start()
# 主進程延時1s
time.sleep(1)
print("主進程執行完了")
# 主進程退出之前把所有的子進程銷毀
sub_prcess.terminate()
exit()
```
> 總結: 主進程會等待所有的子進程執行完成程序再退出
##### 獲取進程pid
```
# 獲取進程pid
import multiprocessing
import time
import os
def work():
# 獲取當前進程編號
print("work進程編號:", os.getpid())
# 獲取父進程編號
print("work父進程編號:", os.getppid())
for i in range(10):
print("工作中...")
time.sleep(1)
# 擴展:根據進程編號殺死對應的進程
# os.kill(os.getpid(), 9)
if __name__ == "__main__":
# 獲取當前進程的編號:
print("當前進程編號:", multiprocessing.current_process().pid)
# 創建子進程
sub_process = multiprocessing.Process(target=work)
# 啟動進程
sub_process.start()
# 主進程執行列印信息操作
for i in range(20):
print("我在主進程中執行...")
time.sleep(1)
```
```
運行結果:
當前進程編號: 624
我在主進程中執行...
我在主進程中執行...
我在主進程中執行...
我在主進程中執行...
我在主進程中執行...
我在主進程中執行...
我在主進程中執行...
我在主進程中執行...
我在主進程中執行...
我在主進程中執行...
我在主進程中執行...
work進程編號: 1312
work父進程編號: 624
工作中...
工作中...
工作中...
工作中...
工作中...
工作中...
工作中...
工作中...
工作中...
工作中...
我在主進程中執行...
我在主進程中執行...
我在主進程中執行...
我在主進程中執行...
我在主進程中執行...
我在主進程中執行...
我在主進程中執行...
我在主進程中執行...
我在主進程中執行...
***Repl Closed***
```
##### 進程間通信——Queue
> 可以使用multiprocessing模塊Queue實現多進程之間的數據傳遞,Queue本身是一個消息隊列程序
```
import multiprocessing
if __name__ == "__main__":
# 創建消息隊列
# 3:表示消息隊列的最大個數
queue = multiprocessing.Queue(3)
# 存放數據
queue.put(1)
queue.put("hello")
queue.put([1, 5, 8])
# 總結:隊列可以放入任意類型的數據
# queue.put("xxx": "yyy")
# 放入消息的時候不會進行等待,如果發現隊列滿了不能放入數據,那麼會直接崩潰
# 建議: 放入數據統一使用 put 方法
# queue.put_nowait(("xxx": "yyy"))
# 判斷隊列是否滿了
result = queue.full()
print(result)
# 判斷隊列是否為空,不靠譜(加延時可解決)
result = queue.empty()
print("隊列是否為空:", result)
# 獲取隊列消息個數
size = queue.qsize()
print("消息個數:", size)
# 獲取隊列中的數據
res = queue.get()
print(res)
# 如果隊列空了,那麼使用get方法會等待隊列有消息以後再取值
```
> 消息隊列Queue完成進程間通信的演練
```
import multiprocessing
import time
# 添加數據
def add_data(queue):
for i in range(5):
# 判斷隊列是否滿了
if queue.full():
# 如果滿了跳出循環,不再添加數據
print("隊列滿了")
break
queue.put(i)
print("add:", i)
time.sleep(0.1)
def read_data(queue):
while True:
if queue.qsize == 0:
print("隊列空了")
break
result = queue.get()
print("read:", result)
if __name__ == "__main__":
# 創建消息隊列
queue = multiprocessing.Queue(3)
# 創建添加數據的子進程
add_process = multiprocessing.Process(target=add_data, args=(queue,))
# 創建讀取數據的子進程
read_process = multiprocessing.Process(target=read_data, args=(queue,))
# 啟動進程
add_process.start()
# 主進程等待寫入進程執行完成以後代碼再繼續往下執行
add_process.join()
read_process.start()
```
##### 進程池Pool
###### 進程池的概念
> 池子裡面放的是進程,進程池會根據任務執行情況自動創建進程,而且盡量少創建進程,合理利用進程池中的進程完成多任務
> 當需要創建的子進程數量不多時,可以直接利用multiprocess中的Process動態生成多個進程,但如果是上百甚至上千個目標,手動的去創建進程的工作量巨大,此時就可以用到multiprocess模塊提供的Pool方法。
> 初始化Pool時,可以指定一個最大進程數,當有新的請求提到Pool中時,如果池還沒有滿,那麼就會創建一個新的進程用來執行該請求,但如果池中的進程數已經達到指定的最大值,那麼該請求就會等待,直到池中有進程結束,才會用之前的進程來執行新的任務。
###### 進程池同步執行任務
> 進程池同步執行任務表示進程池中的進程在執行任務的時候一個執行完成另外一個才能執行,如果沒有執行完會等待上一個進程執行
> 進程池同步實例代碼
```
import multiprocessing
import time
# 拷貝任務
def work():
print("複製中...", multiprocessing.current_process().pid)
time.sleep(1)
if __name__ == "__main__":
# 創建進程池
#3:進程池中進程的最大個數
pool = multiprocessing.Pool(3)
# 模擬大批量的任務,讓進程池去執行
for i in range(5):
# 循環讓進程池執行對應的work任務
# 同步執行任務,一個任務執行完成以後另外一個任務才能執行
pool.apply(work)
```
```
運行結果:
複製中... 6172
複製中... 972
複製中... 972
複製中... 1624
複製中... 1624
***Repl Closed***
```
###### 進程池非同步執行任務
> 進程池非同步執行任務表示進程池中的進程同時執行任務,進程之間不會等待
> 進程池非同步實例代碼
```
import multiprocessing
import time
# 拷貝任務
def work():
print("複製中...", multiprocessing.current_process().pid)
# 獲取當前進程的守護狀態
# 提示:使用進程池創建的進程時守護主進程的狀態,默認自己通過Process創建的進程是不守護主進程的狀態
# print(multiprocessing.current_process().daemon)
time.sleep(1)
if __name__ == "__main__":
# 創建進程池
# 3:進程池中進程的最大個數
pool = multiprocessing.Pool(3)
# 模擬大批量的任務,讓進程池去執行
for i in range(5):
# 循環讓進程池執行對應的work任務
# 同步執行任務,一個任務執行完成以後另外一個任務才能執行
# pool.apply(work)
# 非同步執行,任務執行不會等待,多個任務一起執行
pool.apply_async(work)
# 關閉進程池,意思告訴主進程以後不會有新的任務添加進來
pool.close()
# 主進程等待進程池執行完成以後程序再退出
pool.join()
```
```
運行結果:
複製中... 1848
複製中... 12684
複製中... 12684
複製中... 6836
複製中... 6836
***Repl Closed***
```
***
微信公眾號:TechBoard
***
※Python爬蟲之正則表達式
※Python高效數據分析的8個技巧
TAG:Python |