1. 程式人生 > 程式設計 >通過例項解析python建立程序常用方法

通過例項解析python建立程序常用方法

 執行程式時,單執行緒或單程序往往是比較慢的,為加快程式執行速度,我們可以使用多程序,可以理解為多工同時執行,小編的電腦是四核,所以可以設定四個程序。

下面,我們來了解下多程序的使用:

1、使用multiprocessing模組建立程序

  multiprocessing模組提供了一個Process類來代表程序物件,語法如下:

  Process([group[,target[,name[,args[,kwargs]]]]])

  其中,group:引數未使用,值始終是None

  target:表示當前程序啟動時執行的可呼叫物件

  name:為當前程序例項的別名

  args:表示傳遞給target函式的引數元組

  kwargs:表示傳遞給target函式的引數字典

使用多程序的一個簡單例子:

from multiprocessing import Process   # 匯入模組

# 執行子程序程式碼
def test(interval):
  print('我是子程序')
# 執行主程式
def main():
  print('主程序開始')
  # 例項化Procss程序類
  p = Process(target=test,args=(1,))
  # 啟動子程序
  p.start()
  print('主程序結束')

if __name__ == '__main__':
  main()

結果:

主程序開始
主程序結束
我是子程序

  Process的例項p常用的方法除start()外,還有如下常用方法:

  is_alive():判斷程序例項是否還在執行

  join([timeout]):是否等待程序例項執行結束,或等待多少秒

  start():啟動程序例項(建立子程序)

  run():如果沒有給定target引數,對這個物件呼叫start()方法時,就將執行物件中的run()方法

  terminate():不管任務是否完成,立即終止

  Process類還有如下常用屬性:

  name:當前程序例項別名,預設為Process-N,N為從1開始遞增的整數

  pid:當前程序例項的PID值

下面是Process類方法和屬性的使用,建立兩個子程序,分別使用os模組和time模組輸出父程序和子程序的id以及子程序的時間,並呼叫Process類的name和pid屬性:

# -*- coding:utf-8 -*-
from multiprocessing import Process
import time
import os

#兩個子程序將會呼叫的兩個方法
def child_1(interval):
  print("子程序(%s)開始執行,父程序為(%s)" % (os.getpid(),os.getppid()))
  # 計時開始
  t_start = time.time()
  # 程式將會被掛起interval秒
  time.sleep(interval)
  # 計時結束
  t_end = time.time()
  print("子程序(%s)執行時間為'%0.2f'秒"%(os.getpid(),t_end - t_start))

def child_2(interval):
  print("子程序(%s)開始執行,父程序為(%s)" % (os.getpid(),t_end - t_start))

if __name__ == '__main__':
  print("------父程序開始執行-------")
  # 輸出當前程式的ID
  print("父程序PID:%s" % os.getpid())
  # 例項化程序p1
  p1=Process(target=child_1,))
  # 例項化程序p2
  p2=Process(target=child_2,name="mrsoft",args=(2,))
  # 啟動程序p1
  p1.start()
  # 啟動程序p2
  p2.start()
  #同時父程序仍然往下執行,如果p2程序還在執行,將會返回True
  print("p1.is_alive=%s"%p1.is_alive())
  print("p2.is_alive=%s"%p2.is_alive())
  #輸出p1和p2程序的別名和PID
  print("p1.name=%s"%p1.name)
  print("p1.pid=%s"%p1.pid)
  print("p2.name=%s"%p2.name)
  print("p2.pid=%s"%p2.pid)
  print("------等待子程序-------")
  # 等待p1程序結束
  p1.join()
  # 等待p2程序結束
  p2.join()
  print("------父程序執行結束-------")

結果:

------父程序開始執行-------
父程序PID:13808
p1.is_alive=True
p2.is_alive=True
p1.name=Process-1
p1.pid=13360
p2.name=mrsoft
p2.pid=21500
------等待子程序-------
子程序(13360)開始執行,父程序為(13808)
子程序(21500)開始執行,父程序為(13808)
子程序(13360)執行時間為'1.01'秒
子程序(21500)執行時間為'2.00'秒
------父程序執行結束-------

  上述程式碼中,第一次例項化Process類時,會為name屬性預設賦值為Process-1,第二次則預設為Process-2,但由於例項化程序p2時,設定了name屬性為mrsoft,所以p2.name的值為mrsoft。

2、使用Process子類建立程序

  對於一些簡單的小任務,通常使用Process(target=test)方式實現多程序。但如果要處理複雜任務的程序,通常定義一個類,使其繼承Process類,下面是通過使用Process子類建立多個程序。

# -*- coding:utf-8 -*-
from multiprocessing import Process
import time
import os

#繼承Process類
class SubProcess(Process):
  # 由於Process類本身也有__init__初識化方法,這個子類相當於重寫了父類的這個方法
  def __init__(self,interval,name=''):
    # 呼叫Process父類的初始化方法
    Process.__init__(self)
    # 接收引數interval
    self.interval = interval
    # 判斷傳遞的引數name是否存在
    if name:
      # 如果傳遞引數name,則為子程序建立name屬性,否則使用預設屬性
      self.name = name    
  #重寫了Process類的run()方法
  def run(self):
    print("子程序(%s) 開始執行,父程序為(%s)"%(os.getpid(),os.getppid()))
    t_start = time.time()
    time.sleep(self.interval)
    t_stop = time.time()
    print("子程序(%s)執行結束,耗時%0.2f秒"%(os.getpid(),t_stop-t_start))

if __name__=="__main__":
  print("------父程序開始執行-------")
  # 輸出當前程式的ID
  print("父程序PID:%s" % os.getpid())         
  p1 = SubProcess(interval=1,name='mrsoft')
  p2 = SubProcess(interval=2)
  #對一個不包含target屬性的Process類執行start()方法,就會執行這個類中的run()方法,
  #所以這裡會執行p1.run()
  # 啟動程序p1
  p1.start()
  # 啟動程序p2
  p2.start() 
  # 輸出p1和p2程序的執行狀態,如果真正進行,返回True,否則返回False
  print("p1.is_alive=%s"%p1.is_alive())
  print("p2.is_alive=%s"%p2.is_alive())
  #輸出p1和p2程序的別名和PID
  print("p1.name=%s"%p1.name)
  print("p1.pid=%s"%p1.pid)
  print("p2.name=%s"%p2.name)
  print("p2.pid=%s"%p2.pid)
  print("------等待子程序-------")
  # 等待p1程序結束
  p1.join()
  # 等待p2程序結束
  p2.join() 
  print("------父程序執行結束-------")

結果:

------父程序開始執行-------
父程序PID:2512
p1.is_alive=True
p2.is_alive=True
p1.name=mrsoft
p1.pid=20328
p2.name=SubProcess-2
p2.pid=13700
------等待子程序-------
子程序(20328) 開始執行,父程序為(2512)
子程序(13700) 開始執行,父程序為(2512)
子程序(20328)執行結束,耗時1.00秒
子程序(13700)執行結束,耗時2.00秒
------父程序執行結束-------

  上述程式碼中,定義了一個SubProcess子類,繼承multiprocess.Process父類。SubProcess子類中定義了兩個方法:__init__()初始化方法和run()方法,在__init__()初始化方法中,呼叫父類multiprocess.Process的__init__()初始化方法,否則父類的__init__()方法會被覆蓋,無法開啟程序。此外,在SubProcess子類中沒有定義start()方法,但在主程式中卻呼叫了start()方法,此時就會自動執行SubProcess類的run()方法。

3、使用程序池Pool建立程序

  上面我們使用Process類建立了兩個程序,但如果要建立十幾個或者上百個程序,則需要例項化更多的Process類,解決這一問題的方法就是使用multiprocessing模組提供的pool類,即Pool程序池。

  我們先來了解下Pool類的常用方法:

  apply_async(func[,kwds]]):使用非阻塞方式呼叫func()函式(並行執行,阻塞方式必須等待上一個程序退出才能執行下一個程序),args為傳遞給func()函式的引數列表, kwds為傳遞給func()函式的關鍵字引數列表

  apply(func[,kwds]]):使用阻塞方式呼叫func()函式

  close():關閉Pool,使其不再接受新的任務

  terminate():不管任務是否完成,立即終止

  join():主程序阻塞,等待子程序的退出,必須在close或terminate之後使用

  下面通過一個示例演示一下如何通過程序池建立多程序,設定最大程序數為3,使用非阻塞方式執行10個任務:

# -*- coding=utf-8 -*-
from multiprocessing import Pool
import os,time

def task(name):
  print('子程序(%s)執行task %s ...' % ( os.getpid(),name))
  # 休眠1秒
  time.sleep(1)    

if __name__=='__main__':
  print('父程序(%s).' % os.getpid())
  # 定義一個程序池,最大程序數3
  p = Pool(3)    
  # 從0開始迴圈10次  
  for i in range(10):
    # 使用非阻塞方式呼叫task()函式 
    p.apply_async(task,args=(i,))  
  print('等待所有子程序結束...')
  # 關閉程序池,關閉後p不再接收新的請求
  p.close()
  # 等待子程序結束
  p.join()  
  print('所有子程序結束.')

結果:

父程序(3856).
等待所有子程序結束...
子程序(18872)執行task 0 ...
子程序(11220)執行task 1 ...
子程序(10140)執行task 2 ...
子程序(18872)執行task 3 ...
子程序(11220)執行task 4 ...
子程序(10140)執行task 5 ...
子程序(18872)執行task 6 ...
子程序(11220)執行task 7 ...
子程序(10140)執行task 8 ...
子程序(18872)執行task 9 ...
所有子程序結束.

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。