最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深度解析Python線程和進(jìn)程

 更新時(shí)間:2022年04月26日 15:48:03   作者:人在^O^旅途  
這篇文章主要介紹了Python線程和進(jìn)程的相關(guān)知識(shí),包括線程與進(jìn)程的區(qū)別,通過(guò)示例代碼介紹了進(jìn)程與線程的操作方法,需要的朋友可以參考下

什么是進(jìn)程

進(jìn)程就是操作系統(tǒng)中執(zhí)行的一個(gè)程序,操作系統(tǒng)以進(jìn)程為單位分配存儲(chǔ)空間,每個(gè)進(jìn)程都有自己的地址空間、數(shù)據(jù)棧以及其他用于跟蹤進(jìn)程執(zhí)行的輔助數(shù)據(jù),操作系統(tǒng)管理所有進(jìn)程的執(zhí)行,為它們合理的分配資源。

每個(gè)進(jìn)程都有自己的獨(dú)立內(nèi)存空間,不同進(jìn)程通過(guò)進(jìn)程間通信來(lái)通信。由于進(jìn)程比較重量,占據(jù)獨(dú)立的內(nèi)存,所以上下文進(jìn)程間的切換開(kāi)銷(棧、寄存器、虛擬內(nèi)存、文件句柄等)比較大,但相對(duì)比較穩(wěn)定安全。

什么是線程

一個(gè)進(jìn)程還可以擁有多個(gè)并發(fā)的執(zhí)行線索,簡(jiǎn)單的說(shuō)就是擁有多個(gè)可以獲得CPU調(diào)度的執(zhí)行單元,這就是所謂的線程。

CPU調(diào)度和分派的基本單位線程是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位。線程自己基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一組寄存器和棧)。

由于線程在同一個(gè)進(jìn)程下,它們可以共享相同的上下文,因此相對(duì)于進(jìn)程而言,線程間的信息共享和通信更加容易,上下文切換很快,資源開(kāi)銷較少,但相比進(jìn)程不夠穩(wěn)定容易丟失數(shù)據(jù)。

注:當(dāng)然在單核CPU系統(tǒng)中,真正的并發(fā)是不可能的,因?yàn)樵谀硞€(gè)時(shí)刻能夠獲得CPU的只有唯一的一個(gè)線程,多個(gè)線程共享了CPU的執(zhí)行時(shí)間。

線程缺點(diǎn):

多線程也并不是沒(méi)有壞處,站在其他進(jìn)程的角度,多線程的程序?qū)ζ渌绦虿⒉挥押?,因?yàn)樗加昧烁嗟腃PU執(zhí)行時(shí)間,導(dǎo)致其他程序無(wú)法獲得足夠的CPU執(zhí)行時(shí)間;另一方面,站在開(kāi)發(fā)者的角度,編寫(xiě)和調(diào)試多線程的程序都對(duì)開(kāi)發(fā)者有較高的要求,對(duì)于初學(xué)者來(lái)說(shuō)更加困難。

線程與進(jìn)程的區(qū)別

  • 地址空間和其他資源:進(jìn)程間相互獨(dú)立,同一進(jìn)程的各線程間共享。某線程內(nèi)的想愛(ài)你城咋其他進(jìn)程不可見(jiàn)。
  • 通信:進(jìn)程間通信IPC,線程間可以直接讀寫(xiě)進(jìn)程數(shù)據(jù)段來(lái)進(jìn)行通信——需要進(jìn)程同步和互斥手段的輔助,以保證數(shù)據(jù)的一致性。
  • 調(diào)度和切換:線程上下文切換比進(jìn)程上下文切換要快得多。
  • 在多線程操作系統(tǒng)中,進(jìn)程不是一個(gè)可執(zhí)行的實(shí)體

并行與并發(fā)

并行(Parallelism)

并行:指兩個(gè)或兩個(gè)以上事件(或線程)在同一時(shí)刻發(fā)生,是真正意義上的不同事件或線程在同一時(shí)刻,在不同CPU資源呢上(多核),同時(shí)執(zhí)行。

特點(diǎn)

  • 同一時(shí)刻發(fā)生,同時(shí)執(zhí)行。
  • 不存在像并發(fā)那樣競(jìng)爭(zhēng),等待的概念。

并發(fā)(Concurrency)

指一個(gè)物理CPU(也可以多個(gè)物理CPU) 在若干道程序(或線程)之間多路復(fù)用,并發(fā)性是對(duì)有限物理資源強(qiáng)制行使多用戶共享以提高效率。

特點(diǎn)

  • 微觀角度:所有的并發(fā)處理都有排隊(duì)等候,喚醒,執(zhí)行等這樣的步驟,在微觀上他們都是序列被處理的,如果是同一時(shí)刻到達(dá)的請(qǐng)求(或線程)也會(huì)根據(jù)優(yōu)先級(jí)的不同,而先后進(jìn)入隊(duì)列排隊(duì)等候執(zhí)行。
  • 宏觀角度:多個(gè)幾乎同時(shí)到達(dá)的請(qǐng)求(或線程)在宏觀上看就像是同時(shí)在被處理。

Python中的多進(jìn)程

Python中進(jìn)程操作

process模塊是一個(gè)創(chuàng)建進(jìn)程的模塊,借助這個(gè)模塊,就可以完成進(jìn)程的創(chuàng)建。

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

由該類實(shí)例化得到的對(duì)象,表示一個(gè)子進(jìn)程中的任務(wù)(尚未啟動(dòng))。

注意:

  1. 必須使用關(guān)鍵字方式來(lái)指定參數(shù);
  2. args指定的為傳給target函數(shù)的位置參數(shù),是一個(gè)元祖形式,必須有逗號(hào)。

參數(shù)介紹:

  • group:參數(shù)未使用,默認(rèn)值為None。
  • target:表示調(diào)用對(duì)象,即子進(jìn)程要執(zhí)行的任務(wù)。
  • args:表示調(diào)用的位置參數(shù)元祖。
  • kwargs:表示調(diào)用對(duì)象的字典。如kwargs = {'name':Jack, 'age':18}。
  • name:子進(jìn)程名稱。

代碼展示:

import os
from multiprocessing import Process
def func_one():
    print("第一個(gè)子進(jìn)程")
    print("子進(jìn)程(一)大兒子:%s  父進(jìn)程:%s" % (os.getpid(), os.getppid()))
def func_two():
    print("第二個(gè)子進(jìn)程")
    print("子進(jìn)程(二)二兒子:%s  父進(jìn)程:%s" % (os.getpid(), os.getppid()))
if __name__ == '__main__':
    p_one = Process(target=func_one)
    P_two = Process(target=func_two)
    p_one.start()
    P_two.start()
    print("子進(jìn)程:%s  父進(jìn)程:%s" % (os.getpid(), os.getppid()))  

繼承Process的方式開(kāi)啟進(jìn)程的方式:

import os
from multiprocessing import Process
def func_one():
    print("第一個(gè)子進(jìn)程")
    print("子進(jìn)程(一)大兒子:%s  父進(jìn)程:%s" % (os.getpid(), os.getppid()))
def func_two():
    print("第二個(gè)子進(jìn)程")
    print("子進(jìn)程(二)二兒子:%s  父進(jìn)程:%s" % (os.getpid(), os.getppid()))
if __name__ == '__main__':
    p_one = Process(target=func_one)
    P_two = Process(target=func_two)
    p_one.start()
    P_two.start()
    print("子進(jìn)程:%s  父進(jìn)程:%s" % (os.getpid(), os.getppid()))  

線程

Python的threading模塊

在Python早期的版本中就引入了thread模塊(現(xiàn)在名為_(kāi)thread)來(lái)實(shí)現(xiàn)多線程編程,然而該模塊過(guò)于底層,而且很多功能都沒(méi)有提供,因此目前的多線程開(kāi)發(fā)我們推薦使用threading模塊,該模塊對(duì)多線程編程提供了更好的面向?qū)ο蟮姆庋b。

from random import randint
from threading import Thread
from time import time, sleep
def download(filename):
    print('開(kāi)始下載%s...' % filename)
    time_to_download = randint(5, 10)
    sleep(time_to_download)
    print('%s下載完成! 耗費(fèi)了%d秒' % (filename, time_to_download))
def main():
    start = time()
    t1 = Thread(target=download, args=('Python從入門到住院.pdf',))
    t1.start()
    t2 = Thread(target=download, args=('Peking Hot.avi',))
    t2.start()
    #join阻塞完成任務(wù)
    t1.join()
    t2.join()
    end = time()
    print('總共耗費(fèi)了%.3f秒' % (end - start))
if __name__ == '__main__':
    main()

我們可以直接使用threading模塊的Thread類來(lái)創(chuàng)建線程,但是我們之前講過(guò)一個(gè)非常重要的概念叫“繼承”,我們可以從已有的類創(chuàng)建新類,因此也可以通過(guò)繼承Thread類的方式來(lái)創(chuàng)建自定義的線程類,然后再創(chuàng)建線程對(duì)象并啟動(dòng)線程。

代碼如下所示:

from random import randint
from threading import Thread
from time import time, sleep
class DownloadTask(Thread):
    def __init__(self, filename):
        super().__init__()
        self._filename = filename
    def run(self):
        print('開(kāi)始下載%s...' % self._filename)
        time_to_download = randint(5, 10)
        sleep(time_to_download)
        print('%s下載完成! 耗費(fèi)了%d秒' % (self._filename, time_to_download))
def main():
    start = time()
    t1 = DownloadTask('Python從入門到住院.pdf')
    t1.start()
    t2 = DownloadTask('Peking Hot.avi')
    t2.start()
    t1.join()
    t2.join()
    end = time()
    print('總共耗費(fèi)了%.2f秒.' % (end - start))
if __name__ == '__main__':
    main()

鎖Lock:

模擬場(chǎng)景:

演示了100個(gè)線程向同一個(gè)銀行賬戶轉(zhuǎn)賬(轉(zhuǎn)入1元錢)的場(chǎng)景,在這個(gè)例子中,銀行賬戶就是一個(gè)臨界資源,在沒(méi)有保護(hù)的情況下我們很有可能會(huì)得到錯(cuò)誤的結(jié)果。

from time import sleep
from threading import Thread
class Account(object):
    #初始化賬戶余額為0元
    def __init__(self):
        self._balance = 0
    # 存款函數(shù)
    def deposit(self, money):
        # 計(jì)算存款后的余額
        new_balance = self._balance + money
        # 模擬受理存款業(yè)務(wù)需要0.01秒的時(shí)間
        sleep(0.01)
        # 修改賬戶余額
        self._balance = new_balance
    # set和get
    @property
    def balance(self):
        return self._balance
class AddMoneyThread(Thread):
    def __init__(self, account, money):
        super().__init__()
        self._account = account
        self._money = money
    def run(self):
        self._account.deposit(self._money)
def main():
    # 創(chuàng)建對(duì)象
    account = Account()
    threads = []
    # 創(chuàng)建100個(gè)存款的線程向同一個(gè)賬戶中存錢
    for _ in range(100):
        t = AddMoneyThread(account, 1)
        threads.append(t)
        t.start()
    # 等所有存款的線程都執(zhí)行完畢
    for t in threads:
        t.join()
    print('賬戶余額為: ¥%d元' % account.balance)
if __name__ == '__main__':
    main()

運(yùn)行結(jié)果:

100個(gè)線程分別向賬戶中轉(zhuǎn)入1元錢,結(jié)果居然遠(yuǎn)遠(yuǎn)小于100元。

之所以出現(xiàn)這種情況是因?yàn)槲覀儧](méi)有對(duì)銀行賬戶這個(gè)“臨界資源”加以保護(hù),多個(gè)線程同時(shí)向賬戶中存錢時(shí),會(huì)一起執(zhí)行到new_balance = self._balance + money這行代碼,多個(gè)線程得到的賬戶余額都是初始狀態(tài)下的0,所以都是0上面做了+1的操作,因此得到了錯(cuò)誤的結(jié)果。

在這種情況下,“鎖”就可以派上用場(chǎng)了。我們可以通過(guò)“鎖”來(lái)保護(hù)“臨界資源”,只有獲得“鎖”的線程才能訪問(wèn)“臨界資源”,而其他沒(méi)有得到“鎖”的線程只能被阻塞起來(lái),直到獲得“鎖”的線程釋放了“鎖”,其他線程才有機(jī)會(huì)獲得“鎖”,進(jìn)而訪問(wèn)被保護(hù)的“臨界資源”。

加鎖:

from time import sleep
from threading import Thread, Lock
class Account(object):
    def __init__(self):
        self._balance = 0
        self._lock = Lock()
    def deposit(self, money):
        # 先獲取鎖才能執(zhí)行后續(xù)的代碼
        self._lock.acquire()
        try:
            new_balance = self._balance + money
            sleep(0.01)
            self._balance = new_balance
        finally:
            # 在finally中執(zhí)行釋放鎖的操作保證正常異常鎖都能釋放
            self._lock.release()
    @property
    def balance(self):
        return self._balance
class AddMoneyThread(Thread):
    def __init__(self, account, money):
        super().__init__()
        self._account = account
        self._money = money
    def run(self):
        # 運(yùn)行存錢業(yè)務(wù),只有獲取鎖的才能執(zhí)行
        self._account.deposit(self._money)
def main():
    account = Account()
    threads = []
    #創(chuàng)建100個(gè)線程
    for _ in range(100):
        # 線程加錢
        t = AddMoneyThread(account, 1)
        threads.append(t)
        t.start()
    for t in threads:
        t.join()
    print('賬戶余額為: ¥%d元' % account.balance)
if __name__ == '__main__':
    main()

結(jié)果:賬戶余額為: ¥100元

比較遺憾的一件事情是Python的多線程并不能發(fā)揮CPU的多核特性,因?yàn)镻ython的解釋器有一個(gè)“全局解釋器鎖”(GIL)的東西,任何線程執(zhí)行前必須先獲得GIL鎖,然后每執(zhí)行100條字節(jié)碼,解釋器就自動(dòng)釋放GIL鎖,讓別的線程有機(jī)會(huì)執(zhí)行。

全局解釋器鎖(GIL)

GIL是一個(gè)互斥鎖,它防止多個(gè)線程同時(shí)執(zhí)行Python字節(jié)碼。這個(gè)鎖是必要的,主要是因?yàn)镃Python的內(nèi)存管理不是線程安全的 盡管Python完全支持多線程編程, 但是解釋器的C語(yǔ)言實(shí)現(xiàn)部分在完全并行執(zhí)行時(shí)并不是線程安全的。

因此,解釋器實(shí)際上被一個(gè)全局解釋器鎖保護(hù)著,它確保任何時(shí)候都只有一個(gè)Python線程執(zhí)行。在多線程環(huán)境中,Python 虛擬機(jī)按以下方式執(zhí)行:

  • 設(shè)置GIL
  • 切換到一個(gè)線程去執(zhí)行
  • 運(yùn)行

由于GIL的存在,Python的多線程不能稱之為嚴(yán)格的多線程。因?yàn)槎嗑€程下每個(gè)線程在執(zhí)行的過(guò)程中都需要先獲取GIL,保證同一時(shí)刻只有一個(gè)線程在運(yùn)行。

由于GIL的存在,即使是多線程,事實(shí)上同一時(shí)刻只能保證一個(gè)線程在運(yùn)行,既然這樣多線程的運(yùn)行效率不就和單線程一樣了嗎,那為什么還要使用多線程呢?

由于以前的電腦基本都是單核CPU,多線程和單線程幾乎看不出差別,可是由于計(jì)算機(jī)的迅速發(fā)展,現(xiàn)在的電腦幾乎都是多核CPU了,最少也是兩個(gè)核心數(shù)的,這時(shí)差別就出來(lái)了:通過(guò)之前的案例我們已經(jīng)知道,即使在多核CPU中,多線程同一時(shí)刻也只有一個(gè)線程在運(yùn)行,這樣不僅不能利用多核CPU的優(yōu)勢(shì),反而由于每個(gè)線程在多個(gè)CPU上是交替執(zhí)行的,導(dǎo)致在不同CPU上切換時(shí)造成資源的浪費(fèi),反而會(huì)更慢。即原因是一個(gè)進(jìn)程只存在一把gil鎖,當(dāng)在執(zhí)行多個(gè)線程時(shí),內(nèi)部會(huì)爭(zhēng)搶gil鎖,這會(huì)造成當(dāng)某一個(gè)線程沒(méi)有搶到鎖的時(shí)候會(huì)讓cpu等待,進(jìn)而不能合理利用多核cpu資源。

但是在使用多線程抓取網(wǎng)頁(yè)內(nèi)容時(shí),遇到IO阻塞時(shí),正在執(zhí)行的線程會(huì)暫時(shí)釋放GIL鎖,這時(shí)其它線程會(huì)利用這個(gè)空隙時(shí)間,執(zhí)行自己的代碼,因此多線程抓取比單線程抓取性能要好,所以我們還是要使用多線程的。

參考文章:

深度解析Python線程和進(jìn)程 - wyh草樣 - 博客園

Python-100-Days/13.進(jìn)程和線程.md at master · jackfrued/Python-100-Days · GitHub

到此這篇關(guān)于Python深度解析線程和進(jìn)程的文章就介紹到這了,更多相關(guān)python線程和進(jìn)程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python實(shí)現(xiàn)去除列表中重復(fù)元素的方法總結(jié)【7種方法】

    Python實(shí)現(xiàn)去除列表中重復(fù)元素的方法總結(jié)【7種方法】

    今天小編就為大家分享一篇關(guān)于Python實(shí)現(xiàn)去除列表中重復(fù)元素的方法總結(jié)【7種方法】,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-02-02
  • Python中的sys.stdout.write實(shí)現(xiàn)打印刷新功能

    Python中的sys.stdout.write實(shí)現(xiàn)打印刷新功能

    今天小編就為大家分享一篇Python中的sys.stdout.write實(shí)現(xiàn)打印刷新功能,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-02-02
  • Jmeter如何使用BeanShell取樣器調(diào)用Python腳本

    Jmeter如何使用BeanShell取樣器調(diào)用Python腳本

    這篇文章主要介紹了Jmeter使用BeanShell取樣器調(diào)用Python腳本,文章圍繞Jmeter調(diào)用Python腳本的相關(guān)詳情展開(kāi)標(biāo)題內(nèi)容,需要的小伙伴可以參考一下
    2022-03-03
  • 如何測(cè)試Python網(wǎng)站的訪問(wèn)速度,并且優(yōu)化Python網(wǎng)站的性能

    如何測(cè)試Python網(wǎng)站的訪問(wèn)速度,并且優(yōu)化Python網(wǎng)站的性能

    本文使用網(wǎng)絡(luò)工具和Python測(cè)速庫(kù)進(jìn)行測(cè)試Python網(wǎng)站的訪問(wèn)速度,通過(guò)優(yōu)化代碼性能和優(yōu)化服務(wù)器性能以及優(yōu)化數(shù)據(jù)庫(kù)性能等有針對(duì)性地優(yōu)化Python網(wǎng)站的性能
    2024-01-01
  • Python Django教程之模板的使用

    Python Django教程之模板的使用

    模板是 Django MVT 結(jié)構(gòu)的第三個(gè)也是最重要的部分。Django中的模板基本上是用HTML,CSS和Javascript編寫(xiě)在.html文件中的。本文將通過(guò)實(shí)例詳細(xì)聊聊Django模板的使用,感興趣的可以
    2022-10-10
  • Python?的?ultralytics?庫(kù)功能及安裝方法

    Python?的?ultralytics?庫(kù)功能及安裝方法

    ultralytics庫(kù)由Ultralytics團(tuán)隊(duì)開(kāi)發(fā),旨在為YOLO系列模型提供高效、靈活且易于使用的工具,本文將詳細(xì)介紹ultralytics庫(kù)的功能、安裝方法、核心模塊以及使用示例,感興趣的朋友一起看看吧
    2025-03-03
  • Python入門篇之字典

    Python入門篇之字典

    在元組和列表中,都是通過(guò)編號(hào)進(jìn)行元素的訪問(wèn),但有的時(shí)候我們按名字進(jìn)行數(shù)據(jù)甚至數(shù)據(jù)結(jié)構(gòu)的訪問(wèn),在python中也提供了內(nèi)置的映射類型--字典。映射其實(shí)就是一組key和value以及之間的映射函數(shù),其特點(diǎn)是:key的唯一性、key與value的一對(duì)多的映射。
    2014-10-10
  • python yield和Generator函數(shù)用法詳解

    python yield和Generator函數(shù)用法詳解

    這篇文章主要介紹了python yield和Generator函數(shù)用法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • python必學(xué)知識(shí)之文件操作(建議收藏)

    python必學(xué)知識(shí)之文件操作(建議收藏)

    python中對(duì)文件、文件夾(文件操作函數(shù))的操作需要涉及到os模塊和shutil模塊。下面這篇文章主要給大家介紹了關(guān)于python必學(xué)知識(shí)之文件操作的相關(guān)資料,需要的朋友可以參考下
    2021-05-05
  • Python算法之求n個(gè)節(jié)點(diǎn)不同二叉樹(shù)個(gè)數(shù)

    Python算法之求n個(gè)節(jié)點(diǎn)不同二叉樹(shù)個(gè)數(shù)

    本文先向大家分享了建立二叉樹(shù)的簡(jiǎn)單代碼,其次介紹了Python計(jì)算n個(gè)節(jié)點(diǎn)不同二叉樹(shù)個(gè)數(shù)的問(wèn)題及實(shí)現(xiàn)代碼示例,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-10-10

最新評(píng)論

乌鲁木齐市| 唐山市| 青阳县| 龙陵县| 托里县| 金塔县| 连云港市| 镇江市| 仪征市| 汾西县| 任丘市| 股票| 黑水县| 陆河县| 宜宾市| 永城市| 穆棱市| 克山县| 阿瓦提县| 阳信县| 新乡县| 阿克| 桂阳县| 镶黄旗| 尼玛县| 五常市| 富源县| 徐汇区| 遵义县| 宁城县| 孟州市| 林周县| 汉沽区| 泉州市| 道孚县| 宜兰市| 胶州市| 彭州市| 吉木乃县| 平定县| 龙游县|