2018-08-04(15.5)多線程

python基礎(chǔ)語法(15.5)

多線程

初步了解多線程

(個人理解)電腦的cpu一般情況下一次只能給一個進程提供服務(wù),它給每個進程提供服務(wù)的時間是相同的,到達時間后就會給下一個進程提供服務(wù),這種行為被稱之為時間片輪轉(zhuǎn)。但是由于cpu的速度實在太快了,所以造成看似好像是所有程序一起并發(fā)執(zhí)行。

但是有些時候,有些程序較為耗費資源,一般cpu輪轉(zhuǎn)提供給它的服務(wù)不足以支撐它運行。這時候他就會開多天線程,cpu會輪轉(zhuǎn)給每個線程提供單位時間的服務(wù)。如此一來就可以讓該程序獲得更多的資源。

線程是應(yīng)用程序中工作的最小單位。Python當(dāng)前的多線程庫沒有實現(xiàn)優(yōu)先級,線程組,線程也不能被停止,暫停,恢復(fù),中斷。

多線程具有以下有點:

  • 使用線程可以把程序中長時間占用資源的任務(wù)放到后臺處理。
  • 可以讓顯示界面更加靈活,通過點擊等事件去觸發(fā)一些線程,并且可以在線程進行的過程中給用戶相應(yīng)的反饋。
  • 提升程序運行速度。
  • 一些不需要連續(xù)使用系統(tǒng)資源的任務(wù),系統(tǒng)可以在任務(wù)間歇將CPU分配給其它進程,更好的利用系統(tǒng)資源。

如何使用多線程

Python的標(biāo)準(zhǔn)庫給我們提供了兩個標(biāo)準(zhǔn)模塊:_thread 和threading。

_thread是低級模塊,threading是高級模塊,它對 _thread 進行了封裝,我們常用threading模塊。

threading提供的類

Thread

該類可以按一下兩種方式安全的進行子類化:

  1. 通過將可調(diào)用對象傳遞給構(gòu)造函數(shù)。
  2. 通過重寫子類中的run()方法。

這是一個構(gòu)造函數(shù),調(diào)用它需要傳入關(guān)鍵字參數(shù),其中

? *group默認為空,為ThreadGroup將來擴展保留的。

? *target是run()調(diào)用的可調(diào)用的對象方法。默認為none,表示不調(diào)用任何內(nèi)容。

? *name是線程名稱,默認情況下,構(gòu)造函數(shù)的唯一名稱,形式為“Thread-N”,其中N是小十進制數(shù)。

? *args是目標(biāo)調(diào)用的參數(shù)元組,默認為()

? *kwargs是目標(biāo)關(guān)鍵字參數(shù)的字典調(diào)用,默認為{}

? 如果子類重寫構(gòu)造函數(shù),則必須確保調(diào)用積累構(gòu)造函數(shù)(Thread_init_())

Lock

Rlock

Condition

Event

Timer

local

[Bounded]Semaphore

實例方法

  • isAlive():返回線程是否在運行,在啟動后,終止前都稱之為運行。

  • get/setName(name):獲取/設(shè)置線程名

  • start()“線程準(zhǔn)備就緒,等待CPU調(diào)度

  • join([timeout]):阻塞當(dāng)前的上下文環(huán)境的線程,直到調(diào)用此方法的線程終止或達到指定的timeout(可選參數(shù))

    • 上下文

    每個線程都有屬于它的一組CPU寄存器,稱之為線程的上下文,上下文反應(yīng)了線程上次運行該線程的CPU寄存器狀態(tài)。

    指令指針和堆棧指針寄存器是線程上下文中兩個重要的寄存器,線程總是在進程得到的上下文中運行的,這些地址都用于標(biāo)注擁有線程的進程地址空間中的內(nèi)存。

threading模塊提供的常量

在threading.TIMEOUT_MAX設(shè)置threading全局超時時間。

以函數(shù)的形式來開啟線程

import threading 
import time
#將要執(zhí)行的方法作為參數(shù)傳遞給Thread的構(gòu)造方法
def action(arg):
    time.sleep(1)
    print(threading.current_thread()) # 返回當(dāng)前的線程對象
    
    print("The arg is:{0}".format(arg))#注意是format不是formate

for i in range(4):
    t = threading.Thread(target = action,args = (i,)) # 創(chuàng)建調(diào)用action的線程
    t.start() # 就緒線程,會自動執(zhí)行run()來運行線程
    
if __name__ == "__main__":
    print(threading.current_thread())
    print("main thread End")

運行結(jié)果:

<_MainThread(MainThread, started 24928)>
main thread End
<Thread(Thread-1, started 15260)>
The arg is :0
<Thread(Thread-2, started 18576)>
<Thread(Thread-3, started 19916)>
The arg is :2
The arg is :1
<Thread(Thread-4, started 296)>
The arg is :3

用類來包裝線程對象

即自己定義一個類來繼承Thread,通過重寫run()方法來開啟多線程。

代碼實例:

class MyThread(threading.Thread):
    def __init__(self,arg):
        super(MyThread,self).__init__() #調(diào)用父類
        self.arg = arg #初始化傳入?yún)?shù)
    def run(self): #重寫該方法,定義每個線程要運行的函數(shù)
        time.sleep(1)
        print("The arg is :{0}".format(self.arg))
for i in range(4):
    t = MyThread(i)
    t.start()

運行結(jié)果:

The arg is :0
The arg is :2
The arg is :1
The arg is :3

threading模塊提供的常用方法:

  • threading.currentThread():返回當(dāng)前的線程變量。
  • threading.enumerate():返回一個包含正在運行的線程的list。(正在運行的線程是指線程啟動后,結(jié)束前,不包括啟動前和終止后的線程。)
  • threading.active Count():返回正在運行的線程數(shù)量,與len(threading.enumerate())有相同的結(jié)果。

后臺線程與前臺線程

is/setDeamon(bool):獲取/設(shè)置是否為后臺線程(默認為前臺線程(False))。

注: 在start()之前設(shè)置

區(qū)別:

  1. 后臺線程,主線程結(jié)束,后臺線程立刻停止。
  2. 前臺線程,主線程結(jié)束,等待前臺線程執(zhí)行完程序停止。

相同點:

? 不論是前臺還是后臺,在主線程運行時它們也運行。

代碼實例:

if __name__ == '__main__':
    for i in range(4):
        t = MyThread(i)
        t.setDaemon(True)
        t.start()

    print('main thread end!')

運行結(jié)果:

main thread end!

如果設(shè)置為前臺線程,運行結(jié)果為:

main thread end!
The arg is :0
The arg is :1
The arg is :3
The arg is :2

join() 線程阻塞

該方法會阻塞當(dāng)前上下文環(huán)境線程,直到調(diào)用此方法的線程終止或者到達指定的timeout。即使設(shè)置了setDeamon(True)主線程依舊要等待子線程結(jié)束。

** 線程必須先start()然后再join()**

代碼實例:

if __name__ == '__main__':
    th=[]
    for i in range(100):
        t = MyThread(i)
        th.append(t)
        t.start()
        ```
        不能直接寫成t.join(),這樣只會阻塞主線程一次,無法確保再阻塞過程中線程都執(zhí)行完。
        下面的for循環(huán)時要阻塞主線程,創(chuàng)建的線程數(shù)那么多次,可以保證主線程最后執(zhí)行完。
        這種不同于再上面的for循環(huán)里寫join(),寫在上面會使每個線程不光阻塞主線程,也阻塞接下來的線程。時多線程無意義。
        ```
    for tt in th:
        tt.join()
    #設(shè)置join之后,主線程等待子線程全部執(zhí)行完成后或者子線程超時后,主線程才結(jié)束
    print('main thread end!')
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • 又來到了一個老生常談的問題,應(yīng)用層軟件開發(fā)的程序員要不要了解和深入學(xué)習(xí)操作系統(tǒng)呢? 今天就這個問題開始,來談?wù)劜?..
    tangsl閱讀 4,320評論 0 23
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時...
    歐辰_OSR閱讀 30,231評論 8 265
  • 一、Python簡介和環(huán)境搭建以及pip的安裝 4課時實驗課主要內(nèi)容 【Python簡介】: Python 是一個...
    _小老虎_閱讀 6,329評論 0 10
  • 進程與線程的區(qū)別 現(xiàn)在,多核CPU已經(jīng)非常普及了,但是,即使過去的單核CPU,也可以執(zhí)行多任務(wù)。由于CPU執(zhí)行代碼...
    蘇糊閱讀 843評論 0 2
  • 目 錄 |惟有蘭花香正好 上一章 |青涯使 文 |唐媽 長途跋涉了一整天,又被外頭的小怪物們追著跑了半天,加上還...
    唐媽閱讀 1,644評論 5 34

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