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

Python進階之多線程的實現(xiàn)方法總結

 更新時間:2023年04月14日 10:30:56   作者:生魚同學  
在python中主要有兩種實現(xiàn)多線程的方式:通過threading.Thread?()?方法創(chuàng)建線程和通過繼承?threading.Thread?類的繼承重寫run方法,接下來我們分別說一下多線程的兩種實現(xiàn)形式吧

線程

想要理解線程的含義,首先我們先看一下百度百科的定義:

線程(英語:thread)是操作系統(tǒng)能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。一條線程指的是進程中一個單一順序的控制流,一個進程中可以并發(fā)多個線程,每條線程并行執(zhí)行不同的任務。

簡單來講,當你打開電腦中的一個應用程序,其實此時計算機就為你創(chuàng)建了一個進程,系統(tǒng)會為其進行資源分配并且對其進行調度。而線程就是比進程還要小的單位,多個線程完成不同的工作組成了我們宏觀上能夠得到響應的工作結果。

舉個例子,進程就像一個大的工廠,工廠中有很多機床設備和場地。而不同的線程就像工廠中工作的工人,工廠為其分配不同的工作來完成一個最終的生產目標。我們可以指派不同的工人做不同的工作或增加工人提高我們的生產效率。

在編程中,線程可以由我們啟用幫助我們完成不同的工作實現(xiàn)多線程并發(fā),提高我們的代碼效率。

Python中的多線程

在python中主要有兩種實現(xiàn)多線程的方式:

  • 通過threading.Thread () 方法創(chuàng)建線程
  • 通過繼承 threading.Thread 類的繼承重寫run方法

接下來我們分別說一下多線程的兩種實現(xiàn)形式。

threading.Thread () 創(chuàng)建線程

為了更直觀的理解這個過程,首先我們先編寫一個正常的函數(shù),完成倒數(shù)5個數(shù)的功能,其中間隔一秒鐘。

def fuc():
    for i in range(5):
        time.sleep(1)

在主函數(shù)中,我們調用Thread()來實例化兩個線程,讓他們同時運行。

if __name__ == '__main__':
    t1 = threading.Thread(target=fuc, args=(1,), daemon=True)
    t2 = threading.Thread(target=fuc, args=(2,), daemon=True)
    t2.start()
    t1.start()

整體代碼如下所示:

import threading
import time


def fuc():
    for i in range(5):
        time.sleep(1)


if __name__ == '__main__':
    t1 = threading.Thread(target=fuc)
    t2 = threading.Thread(target=fuc)
    t2.start()
    t1.start()

我們先不討論調用的函數(shù)以及傳入的參數(shù),先來看一下運行效果:

0
0
11
22
33
44

可以看到,兩個打印的結果基本上是同時出現(xiàn)的,并且出現(xiàn)了混合的情況,證明兩個打印的函數(shù)正在同時進行。

接下來我們就來介紹一下類的初始化參數(shù)以及我們調用的函數(shù):

thread.Thread(group=Nore,targt=None,args=(),kwargs={},*,daemon=None)

在該類中主要由以下幾個參數(shù)組成:

  • group:與ThreadGroup類相關,一般不使用。
  • target:線程調用的對象,就是目標函數(shù),在上述的例子中我們傳入的是我們編寫的函數(shù)fuc。
  • name:線程的名字,默認是Tread-x。
  • args:為目標函數(shù)傳遞關鍵字參數(shù),字典。
  • daemon:用來設置線程是否隨主線程退出而退出,涉及到主線程相關知識,我們稍后介紹。

接下來介紹我們常用的幾個方法:

  • run():表示線程啟動的活動,在第二種繼承寫法中會用到。
  • start():激活線程,使其能夠被調度。
  • join():等待至線程終止,這個方法涉及到主線程的知識,我們稍后介紹。
  • isAlive():返回線程是否活動。
  • getName():返回線程名稱。
  • setName() : 設置線程名稱。

接下來,我們使用上述參數(shù)更改示例,讓函數(shù)獲取一個參數(shù),并為不同的線程設置名字。代碼如下:

import threading
import time


def fuc(num):
    for i in range(5):
        print('接收到參數(shù){}:'.format(num), i)
        time.sleep(1)


if __name__ == '__main__':
	# 傳入參數(shù)及名字
    t1 = threading.Thread(target=fuc, args=(1,), name='t1')
    t2 = threading.Thread(target=fuc, args=(2,), name='t2')
    t1.start()
    print(t1.getName(), '開始運行...')
    t2.start()
    print(t2.getName(), '開始運行...')

運行結果如下:

接收到參數(shù)1:t1 開始運行... 
0
接收到參數(shù)2: t20 開始運行...

接收到參數(shù)1:接收到參數(shù)2: 1 
1
接收到參數(shù)1:接收到參數(shù)2:  2
2
接收到參數(shù)1:接收到參數(shù)2:  33

接收到參數(shù)1:接收到參數(shù)2:  4
4

可以看到,雖然結果很混亂,但是我們傳入的參數(shù)以及獲取的名字都被打印出來了。

另外,這里有兩個注意:

  • trgat參數(shù)接受的是函數(shù)名字不需要加括號。
  • args傳入的執(zhí)行函數(shù)參數(shù)要加括號和逗號,保證其是一個元組。

繼承 threading.Thread 類的線程創(chuàng)建

在上面的例子中,我們已經理解了多線程的一種創(chuàng)建方法。接下來我們來介紹第二種方法,這也是眾多大佬很喜歡的一種方法,通過繼承 threading.Thread 類的線程創(chuàng)建。

class MyThread(threading.Thread):
    def run(self) -> None:
        for i in range(5):
            print(i)
            time.sleep(1)


if __name__ == '__main__':
    t1 = MyThread(name='t1')
    t2 = MyThread(name='t2')
    t1.start()
    t2.start()

運行結果如下:

0
0
11
22
33
44

注意:這里調用的是start方法而不是run方法,否則會編程單線程執(zhí)行。

主線程

在了解了多線程的編程方法之后,我們來介紹一下主線程及相關參數(shù)和方法。

在我們執(zhí)行多線程程序的過程中,存在一個主線程,而我們開辟的其他線程其實都是它的子線程。由主線程主導的工作有以下兩種情況:

  • 由于主線程結束了,強制停止其它線程的工作,但此時其他線程有可能還沒有結束自己的工作。
  • 主線程結束后,等待其他線程結束工作,再停止所有線程的工作。

可以簡單地理解為包工頭,它是這些線程的頭子!其從微觀角度上講掌管了一定的工作流程,它可以選擇是否等待其它工人結束工作再結束整個工作。

而我們可以使用參數(shù)或者方法控制這個過程。

使用daemon參數(shù)控制過程

在上邊的函數(shù)參數(shù)介紹中,提到了daemon參數(shù),其為False時,線程不會隨主線程結束而退出,主線程會等待其結束后再退出。而為True時則不論子線程是否完成了相關工作都會直接退出。

接下來我們看兩個示例,我們修改剛才的示例代碼的daemon參數(shù)為True,表示不論子線程是否完成了工作都強制退出。

import threading
import time


def fuc(num):
    for i in range(5):
        print('接收到參數(shù){}:'.format(num), i)
        time.sleep(1)


if __name__ == '__main__':
    t1 = threading.Thread(target=fuc, args=(1,), name='t1', daemon=True)
    t2 = threading.Thread(target=fuc, args=(2,), name='t2', daemon=True)
    t1.start()
    print(t1.getName(), '開始運行...')
    t2.start()
    print(t2.getName(), '開始運行...')
    print("我是主線程,都給我停下!")

結果如下:

接收到參數(shù)1:t1 0 
開始運行...
接收到參數(shù)2:t2  0
開始運行...
我是主線程,都給我停下!

可以看到,子線程的倒數(shù)還沒有結束,由于主線程結束了,所有線程一起結束了。 這里要注意以下幾點:

  • daemon屬性必須在start( )之前設置。
  • 從主線程創(chuàng)建的所有線程不設置daemon屬性,則默認都是daemon=False。

使用.join()阻塞線程

除此之外,我們還可以調用.join()方法阻塞線程,調用該方法的時候,該方法的調用者線程結束后程序才會終止。

#timeout參數(shù)表明等待的時長,不設置該參數(shù)則默認為一直等待。
join(timeout-=None)

我們來看下面這個示例,我們更改了兩個函數(shù)的倒計時時間,使第一個線程的倒計時時間更長,并對第二個線程進行了阻塞操作。代碼如下:

import threading
import time


def fuc1():
    for i in range(10):
        print(i)
        time.sleep(1)


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


if __name__ == '__main__':
    t1 = threading.Thread(target=fuc1, name='t1', daemon=True)
    t2 = threading.Thread(target=fuc2, name='t2', daemon=True)
    t1.start()
    print(t1.getName(), '開始運行...')
    print('我是二兒子,等等我!')
    t2.start()
    print(t2.getName(), '開始運行...')
    t2.join()
    print("我是主線程,都給我停下!")

結果如下:

0t1
開始運行...
我是二兒子,等等我!
0t2 
開始運行...
11
22
33
44

我是主線程,都給我停下!5

我們可以看到,上述代碼中線程一還沒有結束倒數(shù)十個數(shù),程序就結束了。在此過程中,主線程只等待了第二個線程結束,整個程序就結束了。

線程同步

在多個線程同步運行的情況下,會出現(xiàn)多個線程同時操作一個數(shù)據(jù)的情況。如果兩個線程同時操作同一個變量的話,很容易出現(xiàn)混亂的情況。所以,我們需要一個工具來確保在同一時間只能有一個線程處理數(shù)據(jù)。

線程類提供了鎖來解決問題,當線程申請?zhí)幚砟硞€數(shù)據(jù)時申請一個鎖來控制住當前數(shù)據(jù),結束處理時即將鎖釋放。

threading中的鎖

python的threading中為我們提供了RLock鎖來解決多線程同時處理一個數(shù)據(jù)的問題。在某個時刻,我們可以讓線程申請鎖來保護數(shù)據(jù)此時只能供該線程使用。

為了更好的理解該過程,我們定義一個全局變量,讓每一個線程都對其操作但不設置鎖,觀察變量的變化:

R_LOCK = threading.Lock()
COUNT = 100


class MyThread(threading.Thread):
    def run(self) -> None:
        global COUNT
        #R_LOCK.acquire()
        COUNT -= 10
        time.sleep(1)
        print(self.getName(), COUNT)
        #R_LOCK.release()


if __name__ == '__main__':
    threads = [MyThread() for i in range(10)]
    for t in threads:
        t.start()

結果如下:

Thread-3Thread-10  0Thread-8Thread-7 0Thread-6 0Thread-5Thread-9
Thread-1 0Thread-2 00  0
Thread-4 000

可以看到,我們的數(shù)據(jù)發(fā)生了異常,這并不是我們想要得到的結果,若把鎖給關閉注釋讓其正常運行可以看到以下的正常結果:

Thread-1 90
Thread-2 80
Thread-3 70
Thread-4 60
Thread-5 50
Thread-6 40
Thread-7 30
Thread-8 20
Thread-9 10
Thread-10 0

結語

多線程編程是一個非常重要的編程思想,理解多線程編程有助于我們更好的理解設計模式。

當然,python中的編程并不是真正的多線程執(zhí)行,這涉及到GIL全局解釋鎖相關的知識。所以其針對CPU密集型任務來說并沒有很好的效果,接下來我將會更新相關的內容進行更多的說明。

以上就是Python進階之多線程的實現(xiàn)方法總結的詳細內容,更多關于Python多線程的資料請關注腳本之家其它相關文章!

相關文章

  • Python實現(xiàn)文件只讀屬性的設置與取消

    Python實現(xiàn)文件只讀屬性的設置與取消

    這篇文章主要為大家詳細介紹了Python如何實現(xiàn)設置文件只讀與取消文件只讀的功能,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下
    2023-07-07
  • Python使用爬蟲猜密碼

    Python使用爬蟲猜密碼

    我們可以通過python 來實現(xiàn)這樣一個簡單的爬蟲猜密碼功能。下面就看看如何使用python來實現(xiàn)這樣一個功能,對python爬蟲猜密碼相關知識感興趣的朋友參考下吧
    2016-02-02
  • Python Pandas list列表數(shù)據(jù)列拆分成多行的方法實現(xiàn)

    Python Pandas list列表數(shù)據(jù)列拆分成多行的方法實現(xiàn)

    這篇文章主要介紹了Python Pandas list(列表)數(shù)據(jù)列拆分成多行的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-12-12
  • TCP協(xié)議用在python和wifi模塊之間詳解

    TCP協(xié)議用在python和wifi模塊之間詳解

    這篇文章主要介紹了TCP協(xié)議用在python和wifi模塊之間詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • pip?install?python-Levenshtein失敗的解決

    pip?install?python-Levenshtein失敗的解決

    這篇文章主要介紹了pip?install?python-Levenshtein失敗的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • 詳解如何使用numpy提高Python數(shù)據(jù)分析效率

    詳解如何使用numpy提高Python數(shù)據(jù)分析效率

    NumPy是Python語言的一個第三方庫,其支持大量高維度數(shù)組與矩陣運算。本文主要為大家介紹了如何使用numpy提高python數(shù)據(jù)分析效率,需要的可以參考一下
    2023-04-04
  • python安裝完成后可以進行的后續(xù)步驟和注意事項小結

    python安裝完成后可以進行的后續(xù)步驟和注意事項小結

    本文詳細介紹了安裝Python3后的后續(xù)步驟,包括驗證安裝、配置環(huán)境、安裝包、創(chuàng)建和運行腳本,以及使用虛擬環(huán)境,還強調了注意事項,如系統(tǒng)更新、包管理與安全,感興趣的朋友一起看看吧
    2025-01-01
  • 詳解Django中異步任務之django-celery

    詳解Django中異步任務之django-celery

    這篇文章主要介紹了詳解Django中異步任務之django-celery,本文通過場景分析實例圖文相結合給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • Python優(yōu)化代碼的技巧分享

    Python優(yōu)化代碼的技巧分享

    Python?是?一種用著很爽的語言,Python也有著很多特性和技巧,可以幫助我們編寫更高效、更優(yōu)雅、更易維護的代碼,下面小編為大家整理了一些常用的Python代碼優(yōu)化的簡單小技巧,希望對大家有所幫助
    2023-09-09
  • Python3.6.2調用ffmpeg的方法

    Python3.6.2調用ffmpeg的方法

    今天小編就為大家分享一篇Python3.6.2調用ffmpeg的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-01-01

最新評論

巴林右旗| 乌拉特中旗| 房山区| 柯坪县| 琼中| 鄂伦春自治旗| 高尔夫| 富宁县| 成武县| 保定市| 仁寿县| 历史| 蓬安县| 高邑县| 英德市| 沙河市| 益阳市| 措勤县| 大安市| 南昌县| 绥江县| 九台市| 台安县| 金坛市| 莲花县| 潍坊市| 靖安县| 苍南县| 开封市| 诏安县| 开封县| 枞阳县| 赞皇县| 裕民县| 汨罗市| 开封县| 青冈县| 遂昌县| 英吉沙县| 离岛区| 和平县|