多進程:
Python實現多進程的方式主要有兩種,一種方法是使用os模塊中的fork方法,另一種方法是使用multiprocessing模塊,這兩種方法區別在於前者僅使用於Unix/Linux操作系統,對Windows不支持,後者是跨平臺的實現方式,由於現在許多爬蟲程序都是運行在Linux/Unix操作系統上,所以在這都說一下.
- 使用os模塊中的fork方式實現多進程
Python的os模塊封裝了常見的系統調用,其中就有fork方法,fork方法來自於Unix/Linux系統中提供的fork調用,這個方法 比較 特殊,普通方法都是調用一次,返回一次,而fork方法是調用一次,返回兩次,原因在於操作系統講當前進程(父進 程)複製出一份進程(子進程),這兩個進程幾乎完全相同,於是fork方法分別在父進程和子進程中返回,子進程中永遠 返回0,父進程中返回的是子進程的ID,例如:(其中getpid方法獲取當前進程的ID,getppid方法獲取父進程的id)
返回
2.使用multiprocessing模塊創建多進程
multiprocessing模塊提供了一個process類描述一個進程對象,創建子進程時,只需要傳入一個執行函數和函數的參數,即可完成一個process實例的創建,用start()方法啓動進程,用join()方法實現進程間的同步,例如:
import os
from multiprocessing import Process
# 子進程要執行的代碼
def run_proc(name):
print('name:{},pid:{}'.format(name, os.getpid()))
if __name__ == '__main__':
print('start pid:{}'.format(os.getpid()))
for i in range(5):
p = Process(target=run_proc, args=(str(i),))
print('process will start')
p.start()
p.join()
print('process end')
返回:
start pid:15420
process will start
process will start
process will start
process will start
process will start
name:1,pid:8580
name:0,pid:3200
name:2,pid:14520
name:3,pid:15400
name:4,pid:15656
process end
以上是創建進程的兩種方法,但是如果要啓動大量的子進程,使用進程池批量創建子進程的方式更加常見,以爲當被操作對象數目不大時,可以直接利用multiprocessing中process動態生成多了子進程,如果是上百個,上千個目標,手動去限制進程數量卻又太過繁瑣,這時就需要進程池pool發揮作用了。
3.multiprocessing模塊提供了一個pool類代表進程池對象
pool可以提供指定數量的進程供用戶調用,默認大小是cpu的的核數,當有新的請求提交到pool中時,如果池還沒有滿,n那麼就會創建一個新的進程用來執行該請求;但如果池中的進程數已經達到規定最大值,那麼該請求就會等待,知道池中有進程結束,纔會創建新的進程來處理它,例如:
from multiprocessing import Pool
import os, time, random
def run_task(name):
print('task:{},pid:{} is running...'.format(name, os.getpid()))
time.sleep(random.random() * 3)
print('task {} end'.format(name))
if __name__ == '__main__':
print('process {}.'.format(os.getpid()))
p = Pool(processes=3)
for i in range(5):
p.apply_async(run_task, args=(i,))
print('waiting for all subprocesses done..')
p.close()
p.join()
print('end')
返回:
上述程序先創建了容量爲3的進程池,依次向進程池中添加了5個任務,從運行結果中可以看到雖然添加了5個任務,但是一開始只運行了3個,而且最多運行3個經常,當一個任務結束了,新的任務依次添加進去,任務執行使用的進程依然是原來的進程,這一點通過進程的pid可以看出來。
注意:pool 對象調用join(),方法會等待所有子進程執行完畢,調用join()之前必須調用close(),調用close()之後就不能繼續添加新的process。