多進(jìn)程的概念

進(jìn)程

進(jìn)程的概念

python中的多線程其實(shí)并不是真正的多線程,如果想要充分地使用多核CPU的資源,在python中大部分情況需要使用多進(jìn)程。

進(jìn)程的概念:
     進(jìn)程是程序的一次執(zhí)行過程, 正在進(jìn)行的一個(gè)過程或者說一個(gè)任務(wù),而負(fù)責(zé)執(zhí)行任務(wù)的則是CPU.
    
進(jìn)程的生命周期:
    當(dāng)操作系統(tǒng)要完成某個(gè)任務(wù)時(shí),它會創(chuàng)建一個(gè)進(jìn)程。當(dāng)進(jìn)程完成任務(wù)之后,系統(tǒng)就會撤銷這個(gè)進(jìn)程,收回它所占用的資源。從創(chuàng)建到撤銷的時(shí)間段就是進(jìn)程的生命期

進(jìn)程之間存在并發(fā)性:
    在一個(gè)系統(tǒng)中,同時(shí)會存在多個(gè)進(jìn)程。他們輪流占用CPU和各種資源

并行與并發(fā)的區(qū)別:
    無論是并行還是并發(fā),在用戶看來都是同時(shí)運(yùn)行的,不管是進(jìn)程還是線程,都只是一個(gè)任務(wù)而已, 
真正干活的是CPU,CPU來做這些任務(wù),而一個(gè)cpu(單核)同一時(shí)刻只能執(zhí)行一個(gè)任務(wù)。 
并行:多個(gè)任務(wù)同時(shí)運(yùn)行,只有具備多個(gè)cpu才能實(shí)現(xiàn)并行,含有幾個(gè)cpu,也就意味著在同一時(shí)刻可以執(zhí)行幾個(gè)任務(wù)。 
并發(fā):是偽并行,即看起來是同時(shí)運(yùn)行的,實(shí)際上是單個(gè)CPU在多道程序之間來回的進(jìn)行切換。

同步與異步的概念:
    同步就是指一個(gè)進(jìn)程在執(zhí)行某個(gè)請求的時(shí)候,若該請求需要一段時(shí)間才能返回信息,那么這個(gè)進(jìn)程將會一直等待下去,直到收到返回信息才繼續(xù)執(zhí)行下去。 
    異步是指進(jìn)程不需要一直等下去,而是繼續(xù)執(zhí)行下面的操作,不管其他進(jìn)程的狀態(tài)。當(dāng)有消息返回時(shí)系統(tǒng)會通知進(jìn)行處理,這樣可以提高執(zhí)行的效率。 
    比如:打電話的過程就是同步通信,發(fā)短信時(shí)就是異步通信。

多線程和多進(jìn)程的關(guān)系:
    對于計(jì)算密集型應(yīng)用,應(yīng)該使用多進(jìn)程;
    對于IO密集型應(yīng)用,應(yīng)該使用多線程。線程的創(chuàng)建比進(jìn)程的創(chuàng)建開銷小的多。

創(chuàng)建進(jìn)程

使用multiprocessing.Process
import multiprocessing
import time

def func(arg):
    pname = multiprocessing.current_process().name
    pid = multiprocessing.current_process().pid
    print("當(dāng)前進(jìn)程ID=%d,name=%s" % (pid, pname))

    for i in range(5):
        print(arg)
        time.sleep(1)

if __name__ == "__main__":
    p = multiprocessing.Process(target=func, args=("hello",))
    # p.daemon = True  # 設(shè)為【守護(hù)進(jìn)程】(隨主進(jìn)程的結(jié)束而結(jié)束)
    p.start()

    while True:
        print("子進(jìn)程是否活著?", p.is_alive())
        time.sleep(1)
    print("main over")

通過繼承Process實(shí)現(xiàn)自定義進(jìn)程
import multiprocessing
import os

# 通過繼承Process實(shí)現(xiàn)自定義進(jìn)程
class MyProcess(multiprocessing.Process):
    def __init__(self, name, url):
        super().__init__()
        self.name = name
        self.url = url  # 自定義屬性

    # 重寫run
    def run(self):
        pid = os.getpid()
        ppid = os.getppid()
        pname = multiprocessing.current_process().name
        print("當(dāng)前進(jìn)程name:", pname)
        print("當(dāng)前進(jìn)程id:", pid)
        print("當(dāng)前進(jìn)程的父進(jìn)程id:", ppid)

if __name__ == '__main__':

    # 創(chuàng)建3個(gè)進(jìn)程
    MyProcess("小分隊(duì)1", "").start()
    MyProcess("小分隊(duì)2", "").start()
    MyProcess("小分隊(duì)3", "").start()
    print("主進(jìn)程ID:", multiprocessing.current_process().pid)

    # CPU核數(shù)
    coreCount = multiprocessing.cpu_count()
    print("我的CPU是%d核的" % coreCount)

    # 獲取當(dāng)前活動的進(jìn)程列表
    print(multiprocessing.active_children())
同步異步和進(jìn)程鎖
import multiprocessing
import random
import time

def fn():
    name = multiprocessing.current_process().name
    print("開始執(zhí)行進(jìn)程:", name)
    time.sleep(random.randint(1, 4))
    print("執(zhí)行結(jié)束:", name)

# 多進(jìn)程
# 異步執(zhí)行進(jìn)程
def processAsync():
    p1 = multiprocessing.Process(target=fn, name="小分隊(duì)1")
    p2 = multiprocessing.Process(target=fn, name="小分隊(duì)2")
    p1.start()
    p2.start()

# 同步執(zhí)行
def processSync():
    p1 = multiprocessing.Process(target=fn, name="小分隊(duì)1")
    p2 = multiprocessing.Process(target=fn, name="小分隊(duì)2")
    p1.start()
    p1.join()
    p2.start()
    p2.join()

# 加鎖
def processLock():
    # 進(jìn)程鎖
    lock = multiprocessing.Lock()
    p1 = multiprocessing.Process(target=fn2, name="小分隊(duì)1", args=(lock,))
    p2 = multiprocessing.Process(target=fn2, name="小分隊(duì)2", args=(lock,))
    p1.start()
    p2.start()

def fn2(lock):
    name = multiprocessing.current_process().name
    print("開始執(zhí)行進(jìn)程:", name)

    # 加鎖
    # 方式一
    # if lock.acquire():
    #     print("正在工作...")
    #     time.sleep(random.randint(1, 4))
    #     lock.release()

    # 方式二
    with lock:
        print("%s:正在工作..." % name)
        time.sleep(random.randint(1, 4))

    print("%s:執(zhí)行結(jié)束:"% name)


if __name__ == '__main__':
    # processAsync() # 異步執(zhí)行
    # processSync()  # 同步執(zhí)行
    processLock()  # 加進(jìn)程鎖

使用Semaphore控制進(jìn)程的最大并發(fā)
import multiprocessing
import time

def fn(sem):
    with sem:
        name = multiprocessing.current_process().name
        print("子線程開始:", name)
        time.sleep(3)
        print("子線程結(jié)束:", name)

if __name__ == '__main__':
    sem = multiprocessing.Semaphore(3)
    for i in range(8):
        multiprocessing.Process(target=fn, name="小分隊(duì)%d"%i, args=(sem, )).start()

練習(xí): 多進(jìn)程抓取鏈家 https://sz.lianjia.com/ershoufang/rs/
練習(xí): 多進(jìn)程+多協(xié)程抓取鏈家 https://sz.lianjia.com/ershoufang/rs/
練習(xí): 多線程分頁抓取斗魚妹子 https://www.douyu.com/gapi/rkc/directory/2_201/4
練習(xí): 多進(jìn)程分頁抓取斗魚妹子 https://www.douyu.com/gapi/rkc/directory/2_201/4

matplotlib

matplotlib介紹和簡單使用

Matplotlib是什么
Matplotlib 是一個(gè) Python 的 2D繪圖庫
通過 Matplotlib,開發(fā)者可以僅需要幾行代碼,便可以生成繪圖,直方圖,功率譜,條形圖,錯(cuò)誤圖,散點(diǎn)圖等。
Matplotlib的簡單使用
import matplotlib
from matplotlib import pyplot as plt

# 顯示中文
# 配置字體
matplotlib.rcParams['font.sans-serif'] = ['simhei']
matplotlib.rcParams['font.family'] = 'sans-serif'

# 畫線
# plt.plot([1,2], [3,5])
# plt.plot([1,3,7], [2,5,8])
# plt.plot([1,3,7], [2,5,8], '--')  # 虛線
# xy軸文字
plt.xlabel('x軸')
plt.ylabel('y軸')

# 參數(shù)x:x軸位置
# 參數(shù)height:高度
# 參數(shù)width:默認(rèn)0.8
plt.bar([1], [123], label='bj')
plt.bar([3], [245], label='sz')

plt.legend()  # 繪制

# plt.show() # 顯示
plt.savefig('line') # 保存圖片

練習(xí):爬取51job不同職位的崗位數(shù)量,并用折線圖和條形圖表示出來
url = "https://search.51job.com/list/000000,000000,0000,00,9,99,%s,2,1.html" % job

擴(kuò)展

線程池
import threading
import threadpool

import time
import random

# ================================================================= #
def fn(who):
    tname = threading.current_thread().getName()

    print("%s開始%s..." % (tname, who))
    time.sleep(random.randint(1, 5))
    print("-----%s,%s-----" % (tname, who))

# ================================================================= #
# 請求執(zhí)行結(jié)束回調(diào)
# request=已完成的請求
# result=任務(wù)的返回值
def cb(request, result):
    print("cb", request, result)

if __name__ == '__main__':

    # 創(chuàng)建一個(gè)最大并發(fā)為4的線程池(4個(gè)線程)
    pool = threadpool.ThreadPool(4)

    argsList = ["張三豐", "趙四", "王五", "六爺", "洪七公", "朱重八"]
    # 允許回調(diào)
    requests = threadpool.makeRequests(fn, argsList, callback=cb)

    for req in requests:
        pool.putRequest(req)

    # 阻塞等待全部請求返回(線程池創(chuàng)建的并發(fā)默認(rèn)為【守護(hù)線程】)
    pool.wait()
    print("Over")


進(jìn)程池
import multiprocessing
import random
import time

def fn1(arg, name):
    print("正在執(zhí)行任務(wù)1: {}...".format(arg))
    time.sleep(random.randint(1, 5))
    print("進(jìn)程%d完畢!" % (name))

def fn2(arg, name):
    print("正在執(zhí)行任務(wù)2: {}...".format(arg))
    time.sleep(random.randint(1, 5))
    print("進(jìn)程%d完畢!" % (name))


# 回調(diào)函數(shù)
def onback(result):
    print("得到結(jié)果{}".format(result))

if __name__ == "__main__":
    # 待并發(fā)執(zhí)行的函數(shù)列表
    funclist = [fn1, fn2, fn1, fn2]

    # 創(chuàng)建一個(gè)3并發(fā)的進(jìn)程池
    pool = multiprocessing.Pool(3)

    # 遍歷函數(shù)列表,將每一個(gè)函數(shù)丟入進(jìn)程池中
    for i in range(len(funclist)):
        # 同步執(zhí)行
        # pool.apply(func=funclist[i], args=("hello", i))
        # 異步執(zhí)行
        pool.apply_async(func=funclist[i], args=("hello", i), callback=onback)

    pool.close()  # 關(guān)閉進(jìn)程池,不再接收新的進(jìn)程
    pool.join()  # 令主進(jìn)程阻塞等待池中所有進(jìn)程執(zhí)行完畢

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容