Python多任務之進程

来源:https://www.cnblogs.com/yifchan/archive/2019/10/14/python-1-42.html
-Advertisement-
Play Games

Python多任務之進程,內容包括 Process多進程,使用進程池完成多任務;其中 Process多進程 包括 進程的概念,使用Process完成多任務,進程和線程對比,通過隊列完成進程間通信,進程的狀態,獲取進程id;使用進程池完成多任務 包括 進程池的概念和語法,進程池拷貝文件夾等內容 ...


Process多進程

進程的概念

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

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

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

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

進程的狀態

進程狀態圖

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

 

使用Process完成多任務

進程的使用步驟和線程的使用步驟基本一致;

進程的使用步驟

  1. 導入multiprocessing;
  2. 編寫多任務所所需要的函數;
  3. 創建multiprocessing.Process類的實例對象並傳入函數引用;
  4. 調用實例對象的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()
使用Process完成多任務.py

運行結果:

-----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, args=(q,))
    p1.start()
    time.sleep(1)
    p2.start()


if __name__ == '__main__':
    main()
通過隊列完成進程間通信.py

運行結果:

數據下載完成
處理數據結束,數據為: [11, 22, 33]

 

進程池完成多任務

進程池

進程池的概念

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

進程池的創建
任務數固定且較少,用普通的進程即可;任務數不確定,且比較多,就用進程池;
進程池不會等待進程執行完畢,我們需要使用po.join()讓主進程等待進程池中的進程執行完;且po.close()必須在join前面;

創建進程池語法

# 創建進程池
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()
進程池pool示例.py

執行結果:

----start----
0開始執行,進程號為7812
1開始執行,進程號為9984
2開始執行,進程號為1692
1 執行完畢,耗時0.65
3開始執行,進程號為9984
0 執行完畢,耗時1.08
4開始執行,進程號為7812
2 執行完畢,耗時1.82
5開始執行,進程號為1692
4 執行完畢,耗時1.12
6開始執行,進程號為7812
3 執行完畢,耗時1.35
7開始執行,進程號為9984
7 執行完畢,耗時0.11
8開始執行,進程號為9984
6 執行完畢,耗時0.50
9開始執行,進程號為7812
5 執行完畢,耗時0.65
8 執行完畢,耗時0.70
9 執行完畢,耗時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, old_folder, new_folder))
    # 複製原文件夾中的文件,到新文件夾中
    po.close()
    po.join()


if __name__ == '__main__':
    main()
使用進程池拷貝文件夾

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

 

多任務拷貝文件並顯示進度條

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

顯示進度條思路:

  1. 創建一個隊列;
  2. 往拷貝文件的函數中傳入隊列,拷貝好一個文件就往q中傳入該文件名;
  3. 在主函數中計算listdir()中的所有文件數量;
  4. 在主函數中定義一個num,初始值為0;
  5. 在主函數中定義一個while true,從q中獲取文件每獲取一個文件們就將num+1
  6. 計算,如果num的值大於等於總文件數量,就break;
  7. 使用已拷貝文件數量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, 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()
    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, args=(q, file, old_folder, 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()
多任務拷貝文件並顯示進度條.py

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • [☞ 分享:最全最新的Python學習大禮包 ☜ 點擊查看](https://mp.weixin.qq.com/s?__biz=MzU2MzgyODA4OA==&mid=100000592&idx=1&sn=6ee048d8420d213be8b10b87e58669ee&chksm=7c55074 ...
  • JqueryMobile提交表單到php時,會出現空白頁面,需要手動刷新才會顯示php頁面。 修正方法:form元素中添加data-ajax=“false”。 具體原理:https://blog.csdn.net/qw_xingzhe/article/details/37342887 ...
  • 在模板文件中,可以使用“${{...}}”表達式進行數據轉換,Thymeleaf會使用配置好的數據轉換類,來實現轉換。 例如一個User對象,簡單起見假設有姓名和年齡兩個欄位,對象的toString()方法拼接所有欄位,使用“${user}”會調用對象的 toString()方法得到所有欄位,... ...
  • URL配置(URLconf)就像Django 所支撐網站的目錄。它的本質是URL與要為該URL調用的視圖函數之間的映射表;你就是以這種方式告訴Django,對於客戶端發來的某個URL調用哪一段邏輯代碼對應執行。 簡單的路由配置 註意: 1、使用URL,必須先將應用程式中的視圖函數導入到urls.py ...
  • Thymeleaf表達式語法之常量分為字元串常量、數字常量、布爾值常量、空值常量; 運算符分為算術運算符、關係運算符、條件運算符、無操作符。 ...
  • 只要你在 resources 目錄下放置名為 banner.txt、banner.gif 、banner.jpg 或 banner.png 的文件,Spring Boot 會自動載入,將其作為啟動時列印的 logo。 ...
  • Spring Boot 二十個註解 占據無力擁有的東西是一種悲哀。 Cold on the outside passionate on the insede. 背景:Spring Boot 註解的強大毋庸置疑,使用其註解可以大量減少XML 等複雜的配置文件,令Java 代碼更純,開發更簡單高效,記下 ...
  • 摘要 Guava Cache是Google開源的Java工具集庫Guava里的一款緩存工具,一直覺得使用起來比較簡單,沒想到這次居然還踩了一個坑 背景 功能需求抽象出來很簡單,就是將資料庫的查詢 的結果緩存起來。但同時還有批量請求,為了提高效率,肯定要批量查詢資料庫, 對於的guava cache ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...