[TOC]
# **多進程和守護進程**
## 一 **multiprocessing模塊介紹**
python中的多線程無法利用多核優勢,如果想要充分地使用多核CPU的資源(os.cpu_count()查看),在python中大部分情況需要使用多進程。
Python提供了multiprocessing。 multiprocessing模塊用來開啟子進程,并在子進程中執行我們定制的任務(比如函數),該模塊與多線程模塊threading的編程接口類似。
multiprocessing模塊的功能眾多:支持子進程、通信和共享數據、執行不同形式的同步,>提供了Process、Queue、Pipe、Lock等組件。
>與線程不同,進程沒有任何共享狀態,進程修改的數據,改動僅限于該進程內。
## 二 **Process類的介紹**
**Process類是用來創建進程的類**:由該類實例化得到的對象,可用來開啟一個子進程
### **語法**
~~~
Process([group [, target [, name [, args [, kwargs]]]]])
強調:
1. 需要使用關鍵字的方式來指定參數
2. args指定的為傳給target函數的位置參數,是一個元組形式,必須有逗號
~~~
### **參數介紹:**
~~~
group參數未使用,值始終為None
target表示調用對象,即子進程要執行的任務
args表示調用對象的位置參數元組,args=(1,2,'egon',)
kwargs表示調用對象的字典,kwargs={'name':'egon','age':18}
name為子進程的名稱
~~~
### **方法介紹:**
~~~
p.start():啟動進程
p.terminate():強制終止進程p,可能產生僵尸進程和死鎖
p.is_alive():判斷子進程p是否仍然運行,返回True
p.join([timeout]):主線程阻塞,等待子進程p終止后再繼續,timeout可選。
~~~
### **屬性介紹:**
~~~
p.daemon:讓子進程以守護進程方式運行,必須在p.start()之前設置
p.name:獲取子進程的名稱
p.pid:獲取子進程的pid
~~~
## **三 Process類的使用**
python用multiprocessing創建多進程有兩種方式,一種是使用`Process`類直接創建,一種是繼承`Process`類創建自己的類來使用
**注意:在windows中Process()必須放到# if \_\_name\_\_ == '\_\_main\_\_':下**
### **創建并開啟子進程的方式一**
~~~python
import time,random
from multiprocessing import Process
def piao(name):
print('%s piaoing' %name)
time.sleep(random.randrange(1,5))
print('%s piao end' %name)
if __name__ == '__main__':
#實例化得到2個對象
p1=Process(target=piao,args=('egon',)) #必須加逗號
p2=Process(target=piao,args=('alex',))
#調用對象下start的方法,開啟2個進程
p1.start()
p2.start()
print('主.....')
~~~
**運行結果**
```
主.....
egon piaoing
alex piaoing
egon piao end
alex piao end
```
### **創建并開啟子進程的方式二**
自定義類的時候,必須要實現run方法,因為`Process`中的`start`方法就是調用的`run`方法實現的,當然最好也要用super方法繼承父類的初始化數據.
~~~
import time
import random
from multiprocessing import Process
class Piao(Process):
def __init__(self,name):
super().__init__()
self.name=name
def run(self):
print('%s piaoing' %self.name)
time.sleep(random.randrange(1,5))
print('%s piao end' %self.name)
if __name__ == '__main__':
#實例化得到2個對象
p1=Piao('egon')
p2=Piao('alex')
#調用對象下start的方法,開啟2個進程
p1.start() #start會自動調用run
p2.start()
print('主....')
~~~
運行結果同上
## **四 Process對象的join方法**
在主進程運行過程中如果想并發地執行其他的任務,我們可以開啟子進程,此時主進程的任務與子進程的任務分兩種情況
* 情況一:
在主進程的任務與子進程的任務彼此獨立的情況下,主進程的任務先執行完畢后,主進程還需要等待子進程執行完畢,然后統一回收資源。
* 情況二:
如果主進程的任務在執行到某一個階段時,需要等待子進程執行完畢后才能繼續執行,就需要有一種機制能夠讓主進程檢測子進程是否運行完畢,在子進程執行完畢后才繼續執行,否則一直在原地阻塞,這就是join方法的作用
### 演示代碼:
~~~
from multiprocessing import Process
import time,random,os
def task():
print('%s is piaoing' %os.getpid())
time.sleep(random.randrange(1,3))
print('%s is piao end' %os.getpid())
if __name__ == '__main__':
p1=Process(target=task)
p2=Process(target=task)
p1.start()
p2.start()
p1.join()#等待p停止,才執行下一行代碼
p2.join()
print('主')
#執行結果
6096 is piaoing
9776 is piaoing
6096 is piao end
9776 is piao end
主
~~~
>p.join()是讓主線程等待p的結束,卡住的是主進程而絕非子進程p
可以使用for 循環來簡化代碼
~~~
p_l=[p1,p2,p3,p4]
for p in p_l:
p.start()
for p in p_l:
p.join()
~~~
## **五 守護進程**
關于守護進程需要強調兩點:
其一:守護進程會在主進程代碼執行結束后就終止
其二:守護進程內無法再開啟子進程,否則拋出異常
>如果我們有兩個任務需要并發執行,那么開一個主進程和一個子進程分別去執行就ok了
>如果子進程的任務在主進程任務結束后就沒有存在的必要了,那么該子進程應該在開啟前就被設置成守護進程。
>主進程代碼運行結束,守護進程隨即終止
~~~
from multiprocessing import Process
import time,random
def task(name):
print('%s is piaoing' %name)
time.sleep(random.randrange(1,3))
print('%s is piao end' %name)
if __name__ == '__main__':
p=Process(target=task,args=('egon',))
p.daemon=True #一定要在p.start()前設置
p.start()
print('主......') #只要終端打印出這一行內容,那么守護進程p也就跟著結束掉了
#運行結果:子進程還沒來得及打印,主進程就結束了,子進程也就結束了
主......
~~~
- 基礎部分
- 基礎知識
- 變量
- 數據類型
- 數字與布爾詳解
- 列表詳解list
- 字符串詳解str
- 元組詳解tup
- 字典詳解dict
- 集合詳解set
- 運算符
- 流程控制與循環
- 字符編碼
- 編的小程序
- 三級菜單
- 斐波那契數列
- 漢諾塔
- 文件操作
- 函數相關
- 函數基礎知識
- 函數進階知識
- lambda與map-filter-reduce
- 裝飾器知識
- 生成器和迭代器
- 琢磨的小技巧
- 通過operator函數將字符串轉換回運算符
- 目錄規范
- 異常處理
- 常用模塊
- 模塊和包相關概念
- 絕對導入&相對導入
- pip使用第三方源
- time&datetime模塊
- random隨機數模塊
- os 系統交互模塊
- sys系統模塊
- shutil復制&打包模塊
- json&pickle&shelve模塊
- xml序列化模塊
- configparser配置模塊
- hashlib哈希模塊
- subprocess命令模塊
- 日志logging模塊基礎
- 日志logging模塊進階
- 日志重復輸出問題
- re正則表達式模塊
- struct字節處理模塊
- abc抽象類與多態模塊
- requests與urllib網絡訪問模塊
- 參數控制模塊1-optparse-過時
- 參數控制模塊2-argparse
- pymysql數據庫模塊
- requests網絡請求模塊
- 面向對象
- 面向對象相關概念
- 類與對象基礎操作
- 繼承-派生和組合
- 抽象類與接口
- 多態與鴨子類型
- 封裝-隱藏與擴展性
- 綁定方法與非綁定方法
- 反射-字符串映射屬性
- 類相關內置方法
- 元類自定義及單例模式
- 面向對象的軟件開發
- 網絡-并發編程
- 網絡編程SOCKET
- socket簡介和入門
- socket代碼實例
- 粘包及粘包解決辦法
- 基于UDP協議的socket
- 文件傳輸程序實戰
- socketserver并發模塊
- 多進程multiprocessing模塊
- 進程理論知識
- 多進程與守護進程
- 鎖-信號量-事件
- 隊列與生產消費模型
- 進程池Pool
- 多線程threading模塊
- 進程理論和GIL鎖
- 死鎖與遞歸鎖
- 多線程與守護線程
- 定時器-條件-隊列
- 線程池與進程池(新方法)
- 協程與IO模型
- 協程理論知識
- gevent與greenlet模塊
- 5種網絡IO模型
- 非阻塞與多路復用IO實現
- 帶著目標學python
- Pycharm基本使用
- 爬蟲
- 案例-爬mzitu美女
- 案例-爬小說
- beautifulsoup解析模塊
- etree中的xpath解析模塊
- 反爬對抗-普通驗證碼
- 反爬對抗-session登錄
- 反爬對抗-代理池
- 爬蟲技巧-線程池
- 爬蟲對抗-圖片懶加載
- selenium瀏覽器模擬