python多任務-線程


多任務的概念

什么叫“多任務”呢?簡單地說,就是操作系統可以同時運行多個任務。打個比方,你一邊在用瀏覽器上網,一邊在聽MP3,一邊在用Word趕作業,這就是多任務,至少同時有3個任務正在運行。還有很多任務悄悄地在后台同時運行着,只是桌面上沒有顯示而已。

現在,多核CPU已經非常普及了,但是,即使過去的單核CPU,也可以執行多任務。由於CPU執行代碼都是順序執行的,那么,單核CPU是怎么執行多任務的呢?

答案就是操作系統輪流讓各個任務交替執行,任務1執行0.01秒,切換到任務2,任務2執行0.01秒,再切換到任務3,執行0.01秒……這樣反復執行下去。表面上看,每個任務都是交替執行的,但是,由於CPU的執行速度實在是太快了,我們感覺就像所有任務都在同時執行一樣。

真正的並行執行多任務只能在多核CPU上實現,但是,由於任務數量遠遠多於CPU的核心數量,所以,操作系統也會自動把很多任務輪流調度到每個核心上執行。

注意:

  • 並發:指的是任務數多余cpu核數,通過操作系統的各種任務調度算法,實現用多個任務“一起”執行(實際上總有一些任務不在執行,因為切換任務的速度相當快,看上去一起執行而已)
  • 並行:指的是任務數小於等於cpu核數,即任務真的是一起執行的

線程基礎

python的thread模塊是比較底層的模塊,python的threading模塊是對thread做了一些包裝的,可以更加方便的被使用

單線程執行

import time


def test():
        print("test...")
        time.sleep(1)


if __name__ == '__main__':

        for i in range(5):
                test()

執行效果:程序在控制台每隔一秒打印test...

多線程執行

import time
import threading

def test():
        print("test...")
        time.sleep(1)


if __name__ == '__main__':

        for i in range(5):
                t = threading.Thread(target=test)
                t.start() # 啟動線程
    

執行效果:程序在控制台一下子輸出五行test...,等待1秒左右結束

說明:

  1. 可以明顯看出使用了多線程並發的操作,花費時間要短很多
  2. 當調用start()時,才會真正的創建線程,並且開始執行

主線程會等待所有子線程結束后才結束

import time
import threading


def playPhone():

        print('玩手機...')
        time.sleep(1)


def eat():

        print("吃東西...")
        time.sleep(1)


if __name__ == '__main__':

        print("--開始--")

        t1 = threading.Thread(target=playPhone)
        t1.start()

        t2 = threading.Thread(target=eat)
        t2.start()

        print('--執行結束')

執行效果:主線程阻塞1秒左右后程序結束,說明主線程在等待其他線程執行完畢。

查看線程數量

          print('玩手機...')
                time.sleep(1)


def eat():

        for i in range(10):
                print("吃東西...")
                time.sleep(1)


if __name__ == '__main__':

        print("--開始--")

        t1 = threading.Thread(target=playPhone)
        t1.start()

        t2 = threading.Thread(target=eat)
        t2.start()
    
        # 查看正在執行的線程數量
        while True:
                length = len(threading.enumerate())
                print("當前運行的線程數量:%d" % length)
                print("這些線程是:%s" % str(threading.enumerate()))
    
    
                if length == 1:
                        break
    
                time.sleep(0.5)    

        print('--執行結束')

在python中,調用threading.enumerate()能獲取當前正在運行的所有線程,返回值是一個list,調用length()函數並傳入該list對象就獲取到當前運行線程的數量。

線程-注意點

線程執行代碼的封裝

通過上一篇,能夠看出,通過使用threading模塊能完成多任務的程序開發,為了讓每個線程的封裝性更完美,所以使用threading模塊時,往往會定義一個新的子類class,只要繼承threading.Thread就可以了,然后重寫run方法。

示例如下:

import time
import threading


class MyThread(threading.Thread):

        def run(self):
                for i in range(5):
                        time.sleep(1)
                        print("我是%s@%d" % (self.name, i)) 


if __name__ == "__main__":
        mt = MyThread()
        mt.start()

運行結果如下:

我是Thread-1@0
我是Thread-1@1
我是Thread-1@2
我是Thread-1@3
我是Thread-1@4

python的threading.Thread類有一個run方法,用於定義線程的功能函數,可以在自己的線程類中覆蓋該方法。而創建自己的線程實例后,通過Thread類的start方法,可以啟動該線程,交給python虛擬機進行調度,當該線程獲得執行的機會時,就會調用run方法執行線程。

線程的執行順序

mport time
import threading


class MyThread(threading.Thread):

        def run(self):
                for i in range(5):
                        time.sleep(1)
                        print("我是%s@%d" % (self.name, i)) 


if __name__ == "__main__":
    
        for i in range(5):
                mt = MyThread()
                mt.start()

執行結果(運行的結果可能不一樣,但是大體是一致的):

我是Thread-5@0
我是Thread-2@0
我是Thread-3@0
我是Thread-4@0
我是Thread-1@0
我是Thread-3@1
我是Thread-4@1
我是Thread-2@1
我是Thread-5@1
我是Thread-1@1
我是Thread-3@2
我是Thread-4@2
我是Thread-2@2
我是Thread-5@2
我是Thread-1@2
我是Thread-3@3
我是Thread-4@3
我是Thread-2@3
我是Thread-5@3
我是Thread-1@3
我是Thread-3@4
我是Thread-4@4
我是Thread-5@4
我是Thread-2@4
我是Thread-1@4

從代碼和執行結果我們可以看出,多線程程序的執行順序是不確定的。當執行到sleep語句時,線程將被阻塞(Blocked),到sleep結束后,線程進入就緒(Runnable)狀態,等待調度。而線程調度將自行選擇一個線程執行。上面的代碼中只能保證每個線程都運行完整個run函數,但是線程的啟動順序、run函數中每次循環的執行順序都不能確定。

總結

  1. 每個線程默認有一個名字,盡管上面的例子中沒有指定線程對象的name,但是python會自動為線程指定一個名字。
  2. 當線程的run()方法結束時該線程完成。
  3. 無法控制線程調度程序,但可以通過別的方式來影響線程調度的方式。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM