1. 程式人生 > 程式設計 >Python Process多程序實現過程

Python Process多程序實現過程

程序的概念

程式是沒有執行的程式碼,靜態的;

程序是執行起來的程式,程序是一個程式執行起來之後和資源的總稱;

程式只有一個,但同一份程式可以有多個程序;例如,電腦上多開QQ;

程式和程序的區別在於有沒有資源,程序有資源而程式沒有資源,程序是一個資源分配的基本單元;
程式在沒執行的時候沒有資源,沒有顯示卡,沒有網絡卡,等等;雙擊執行後有攝像頭,有網速等等,就叫做程序;

程序的狀態

程序狀態圖


  • 就緒態:執行的條件都已經慢去,正在等在cpu執行
  • 執行態:cpu正在執行其功能
  • 等待態:等待某些條件滿足,例如一個程式sleep了,此時就處於等待態

使用Process完成多工

程序的使用步驟和執行緒的使用步驟基本一致;

程序的使用步驟:

  • 匯入multiprocessing;
  • 編寫多工所所需要的函式;
  • 建立multiprocessing.Process類的例項物件並傳入函式引用;
  • 呼叫例項物件的start方法,建立子執行緒。

程序使用步驟圖示:

程序使用步驟程式碼

import time
import multiprocessing
def sing():
  while True:
    print("-----sing-----")
    time.sleep(1)
def dance():
  while True:
    print("-----dance-----")
    time.sleep(1)
def main():
  p1 = multiprocessing.Process(target=sing)
  p2 = multiprocessing.Process(target=dance)
  p1.start()
  p2.start()
if __name__ == "__main__":
  main()

執行結果:

-----sing-----
-----dance-----
-----sing-----
-----dance-----
-----sing-----
-----dance-----
......

程序:

  • 主程序有什麼,子程序就會有什麼資源;
  • 執行緒能建立多工,程序也能建立多工,但程序耗費的資源比較大;
  • 所以執行的程序數,不一定越多越好;
  • 當建立子程序時,會複製一份主程序的資源,程式碼,記憶體等,但又會有自己不同的地方,比如pid等;
  • 我們可以理解為多程序之間共享程式碼,即只有一份程式碼,但有多個指向同一程式碼的箭頭;
  • 能共享的就共享,不能共享的就拷貝一份;不需要修改的就共享,要修改的時候就給你拷貝一份,這就是寫時拷貝;

獲取程序id

獲取程序id程式碼

from multiprocessing import Process
import osdef run_proc():
  """子程序要執行的程式碼"""
  print('子程序執行中,pid=%d...' % os.getpid()) # os.getpid獲取當前程序的程序號
  print('子程序將要結束...')

if __name__ == '__main__':
  print('父程序pid: %d' % os.getpid()) # os.getpid獲取當前程序的程序號
  p = Process(target=run_proc)
  p.start()

程序和執行緒對比

程序和執行緒的區別

  • 程序是系統進行資源分配和排程的一個獨立單位;
  • 執行緒是程序的一個實體,是CPU排程和分派的基本單位,即是作業系統排程的單位,它是比程序更小的能獨立執行的基本單位;
  • 一個程式至少有一個程序,一個程序至少有一個執行緒;
  • 執行緒的劃分尺度小於程序(資源比程序少),使得多執行緒程式的併發性高;
  • 程序在執行過程中擁有獨立的記憶體單元,而多個執行緒共享記憶體,從而極大地提高了程式的執行效率;
  • 執行緒不能夠獨立執行,必須依存在程序中;
  • 程序先有,才有的執行緒;
  • 執行緒用資源去做事;
  • 多執行緒能實現多工是指在一個程序資源裡面有多個箭頭;多執行緒是在同一個資源裡面有多個箭頭執行同一份程式碼;
  • 多程序的多工是又開啟了一份資源,在這個資源裡面又有一個箭頭;
  • 程序執行方式1:在一份資源裡面有多個箭頭在執行;
  • 程序執行方式2:有多份資源,在每一份資源裡面有一個箭頭執行程式碼;
  • 執行緒執行開銷小,但不利於資源的管理和保護,程序正好相反;
  • 開發中還是多執行緒用的多;

通過佇列完成程序間通訊

佇列使用語法

# 建立佇列:
from multiprocessing import Queue
q = Queue(3)
# 往佇列中新增資料:
q.put(xxx)
# 從佇列中獲取資料:
q.get()

通過佇列完成程序間通訊程式碼

from multiprocessing import Queue
import multiprocessing
def download_data(q):
  """模擬這是從網上下載資料"""
  data = [11,22,33]
  for i in data:
    q.put(i)
  print("資料下載完成")
def deal_data(q):
  """模擬處理從網上下載下來的資料"""
  data_list = []
  while True:
    data = q.get()
    data_list.append(data)
    if q.empty():
      break
  print("處理資料結束,資料為:",data_list)
def main():
  q = Queue(3)
  p1 = multiprocessing.Process(target=download_data,args=(q,))
  p2 = multiprocessing.Process(target=deal_data,))
  p1.start()
  time.sleep(1)
  p2.start()
if __name__ == '__main__':
  main()

執行結果:

資料下載完成

處理資料結束,資料為: [11,33]

程序池完成多工

程序池

程序池的概念

因為程序的建立和銷燬是需要大量的資源的,為了減少消耗,當我們在處理多工時,比如100個任務,我們可以先建立10個程序,然後用這10個程序來執行者100個任務,就可以重複使用程序,達到節約資源的目的了,而這個就可以使用程序池。

程序池的建立

任務數固定且較少,用普通的程序即可;任務數不確定,且比較多,就用程序池;

程序池不會等待程序執行完畢,我們需要使用po.join()讓主程序等待程序池中的程序執行完;且po.close()必須在join前面;小編整理一套Python資料和PDF,有需要Python學習資料可以加學習群:631441315 ,反正閒著也是閒著呢,不如學點東西啦~~

建立程序池語法

# 建立程序池
from multiprocessing import Pool
po = Pool(3)

# 給程序池傳遞任務和引數
po.asyn(sing,(num,))

# 讓程序池等待子程序執行完
po.close()
po.join()

程序池pool示例

from multiprocessing import Pool
import os,time,random
def worker(msg):
  t_start = time.time()
  print("%s開始執行,程序號為%d" % (msg,os.getpid()))
  # random.random()隨機生成0~1之間的浮點數
  time.sleep(random.random() * 2)
  t_stop = time.time()
  print(msg,"執行完畢,耗時%0.2f" % (t_stop - t_start))
def main():
  po = Pool(3) # 定義一個程序池,最大程序數3
  for i in range(0,10):
    # Pool().apply_async(要呼叫的目標,(傳遞給目標的引數元祖,))
    # 每次迴圈將會用空閒出來的子程序去呼叫目標
    po.apply_async(worker,(i,))

  print("----start----")
  po.close() # 關閉程序池,關閉後po不再接收新的請求
  po.join() # 等待po中所有子程序執行完成,必須放在close語句之後
  print("-----end-----")
if __name__ == '__main__':
  main()

執行結果:

----start----
0開始執行,程序號為7812
1開始執行,程序號為9984
2開始執行,程序號為1692
執行完畢,耗時0.65
3開始執行,程序號為9984
執行完畢,耗時1.08
4開始執行,程序號為7812
執行完畢,耗時1.82
5開始執行,程序號為1692
執行完畢,耗時1.12
6開始執行,程序號為7812
執行完畢,耗時1.35
7開始執行,程序號為9984
執行完畢,耗時0.11
8開始執行,程序號為9984
執行完畢,耗時0.50
9開始執行,程序號為7812
執行完畢,耗時0.65
執行完畢,耗時0.70
執行完畢,耗時0.74
-----end-----

多程序拷貝資料夾

多工資料夾copy

步驟思路:

1.獲取使用者要拷貝的資料夾的名字;

2.建立一個新的資料夾;

3.獲取資料夾的所有待拷貝的檔名;listdir()

4.建立程序池;

5.複製原資料夾中的檔案,到新資料夾的檔案中去;

多工拷貝檔案程式碼

import os
from multiprocessing import Pool
def copy_file(file,old_folder,new_folder):

  old_f = open(old_folder+"/"+file,"rb")
  data = old_f.read()
  old_f.close()

  new_f = open(new_folder+"/"+file,"wb")
  new_f.write(data)
  new_f.close()
  print("建立檔案成功:",file)
def main():
  # 1.獲取要拷貝的資料夾
  old_folder = input("請輸入你要拷貝的資料夾:")
  # 2.建立新資料夾
  new_folder = old_folder + "_復件"
  try:
    os.mkdir(new_folder)
    print("建立資料夾成功")
  except Exception as e:
    pass
  # 3.獲取資料夾中所有待拷貝的檔案,listdir()
  files_list = os.listdir(old_folder)
  # print(files_list)
  # 4.建立程序池
  po = Pool(5)
  for file in files_list:
    # 向程序池中新增複製檔案的任務
    po.apply_async(copy_file,args=(file,new_folder))
  # 複製原資料夾中的檔案,到新資料夾中
  po.close()
  po.join()
if __name__ == '__main__':
  main()

在完成資料夾拷貝後,增加了一個需求,顯示拷貝檔案的進度條,怎麼辦?

多工拷貝檔案並顯示進度條

如果要在程序池中使用Queue,要使用from multiprocessing import Manager ,使用Manager().Queue();

顯示進度條思路:

  • 建立一個佇列;
  • 往拷貝檔案的函式中傳入佇列,拷貝好一個檔案就往q中傳入該檔名;
  • 在主函式中計算listdir()中的所有檔案數量;
  • 在主函式中定義一個num,初始值為0;
  • 在主函式中定義一個while true,從q中獲取檔案每獲取一個檔案們就將num+1
  • 計算,如果num的值大於等於總檔案數量,就break;
  • 使用已拷貝檔案數量num除以總檔案數量,即為拷貝的進度,使用開頭\r 和end=""讓顯示進度不換行,如下:

print("\r已拷貝檔案%.2f %%" % (copy_ok_file_num*100/all_file_len),end="")

多工拷貝檔案並顯示進度條程式碼:

import os
from multiprocessing import Pool,Manager
def copy_file(q,file,new_folder):
  old_f = open(old_folder+"/"+file,"rb")
  data = old_f.read()
  old_f.close()
  new_f = open(new_folder+"/"+file,"wb")
  new_f.write(data)
  new_f.close()
  q.put(file)
def main():
  # 1.獲取要拷貝的資料夾
  old_folder = input("請輸入你要拷貝的資料夾:")
  # 2.建立新資料夾
  new_folder = old_folder + "_復件"
  try:
    os.mkdir(new_folder)
    print("建立資料夾成功")
  except Exception as e:
    pass
  # 3.獲取資料夾中所有待拷貝的檔案,listdir()
  files_list = os.listdir(old_folder)
  # 4.建立程序池
  po = Pool(5)
  # 5.建立佇列
  q = Manager().Queue()
  # 6.複製原資料夾中的檔案,到新資料夾中
  for file in files_list:
    # 向程序池中新增複製檔案的任務
    po.apply_async(copy_file,new_folder))
  all_file_len = len(files_list)
  po.close()
  # po.join()
  copy_ok_file_num = 0
  while True:
    file = q.get()
    copy_ok_file_num += 1
    print("已拷貝檔案%.2f %%" % (copy_ok_file_num*100/all_file_len))
    # print("\r已拷貝檔案%.2f %%" % (copy_ok_file_num*100/all_file_len),end="")
    if copy_ok_file_num >= all_file_len:
      break
  print()
if __name__ == '__main__':
  main()

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