一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Python - Python學習筆記之線程

Python學習筆記之線程

2022-02-26 00:00東山絮柳仔 Python

這篇文章主要介紹了Python線程詳解,本文詳細講解了線程方方面面的知識,如線程基礎知識線程狀態、線程同步(鎖)、線程通信(條件變量)等內容,需要的朋友可以參考下

1.自定義進程

自定義進程類,繼承Process類,重寫run方法(重寫Process的run方法)。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from multiprocessing import Process
import time
import os
class MyProcess(Process):
    def __init__(self, name):  ##重寫,需要__init__,也添加了新的參數。        ##Process.__init__(self) 不可以省略,否則報錯:AttributeError:'XXXX'object has no attribute '_colsed'
        Process.__init__(self)
        self.name = name
    def run(self):
        print("子進程(%s-%s)啟動" % (self.name, os.getpid()))
        time.sleep(3)
        print("子進程(%s-%s)結束" % (self.name, os.getpid()))
if __name__ == '__main__':
    print("父進程啟動")
    p = MyProcess("Ail")
    # 自動調用MyProcess的run()方法
    p.start()
    p.join()
    print("父進程結束")

# 輸出結果
父進程啟動
子進程(Ail-38512)啟動
子進程(Ail-38512)結束
父進程結束

2.進程與線程

多進程適合在CPU密集型操作(CPU操作指令比較多,如科學計算、位數多的浮點計算);

多線程適合在IO密集型操作(讀寫數據操作比較多的,比如爬蟲、文件上傳、下載)

線程是并發,進程是并行:進程之間互相獨立,是系統分配資源的最小單位,同一個進程中的所有線程共享資源。

進程:一個運行的程序或代碼就是一個進程,一個沒有運行的代碼叫程序。進程是系統進行資源分配的最小單位,進程擁有自己的內存空間,所以,進程間數據不共享,開銷大。

進程是程序的一次動態執行過程。每個進程都擁有自己的地址空間、內存、數據棧以及其它用于跟蹤執行的輔助數據。操作系統負責其上所有進程的執行,操作系統會為這些進程合理地分配執行時間。

線程:調度執行的最小單位,也叫執行路徑,不能獨立存在,依賴進程的存在而存在,一個進程至少有一個線程,叫做主線程,多個線程共享內存(數據共享和全局變量),因此提升程序的運行效率。

線程是操作系統能夠進行運算調度的最小單位,它被包含在進程之中,是進程中的實際運作單位。一條線程指的是進程中一個單一順序的控制流,一個進程中可以并發多個線程,每條線程并行執行不同的任務。一個線程是一個execution context(執行上下文),即一個CPU執行時所需要的一串指令。

主線程:主線程就是創建線程進程中產生的第一個線程,也就是main函數對應的線程。

協程:用戶態的輕量級線程,調度由用戶控制,擁有自己的寄存器上下文和棧,切換基本沒有內核切換的開銷,切換靈活。

進程和線程的關系

Python學習筆記之線程

3.多線程

操作系統通過給不同的線程分配時間片(CPU運行時長)來調度線程,當CPU執行完一個線程的時間片后就會快速切換到下一個線程,時間片很短而且切換速度很快,以至于用戶根本察覺不到。多個線程根據分配的時間片輪流被CPU執行,如今絕大多數計算機的CPU都是多核的,多個線程在操作系統的調度下,能夠被多個CPU并行執行,程序的執行速度和CPU的利用效率大大提升。絕大對數主流的編程語言都能很好地支持多線程,然而,Python由于GIL鎖無法實現真正的多線程。

內存中的線程

Python學習筆記之線程

4.Thread類方法

(1)start() --開始執行該線程;

(2)run() --定義線程的方法(開發者可以在子類中重寫);標準的 run() 方法會對作為 target 參數傳遞給該對象構造器的可調用對象(如果存在)發起調用,并附帶從 args 和 kwargs 參數分別獲取的位置和關鍵字參數。

(3)join(timeout=None) --直至啟動的線程終止之前一直掛起;除非給出了timeout(單位秒),否則一直被阻塞;因為 join() 總是返回 None ,所以要在 join() 后調用 is_alive() 才能判斷是否發生超時 -- 如果線程仍然存活,則 join() 超時。一個線程可以被 join() 很多次。如果嘗試加入當前線程會導致死鎖, join() 會引起 RuntimeError 異常。如果嘗試 join() 一個尚未開始的線程,也會拋出相同的異常。

(4)is_alive() --布爾值,表示這個線程是否還存活;當 run() 方法剛開始直到 run() 方法剛結束,這個方法返回 True 。

(5)threading.current_thread()--返回當前對應調用者的控制線程的 Thread 對象。例如,獲取當前線程的名字,可以是current_thread().name

5.多線程與多進程小Case

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from threading import Thread
from multiprocessing import Process
import os
def work():
    print('hello,',os.getpid())
if __name__ == '__main__':
    # 在主進程下開啟多個線程,每個線程都跟主進程的pid一樣
    t1 = Thread(target=work)  # 開啟一個線程
    t2 = Thread(target=work)  # 開啟兩個線程
    t1.start()  ##start()--It must be called at most once per thread object.It arranges for the object's run() method to be                ## invoked in a separate thread of control.This method will raise a RuntimeError if called more than once on the                ## same thread object.
    t2.start()
    print('主線程/主進程pid', os.getpid())
    # 開多個進程,每個進程都有不同的pid
    p1 = Process(target=work)
    p2 = Process(target=work)
    p1.start()
    p2.start()
    print('主線程/主進程pid',os.getpid())

6.Thread 的生命周期

線程的狀態包括:創建、就緒、運行、阻塞、結束。

(1)創建對象時,代表 Thread 內部被初始化;

(2) 調用 start() 方法后,thread 會開始進入隊列準備運行,在未獲得CPU、內存資源前,稱為就緒狀態;輪詢獲取資源,進入運行狀態;如果遇到sleep,則是進入阻塞狀態;

(3) thread 代碼正常運行結束或者是遇到異常,線程會終止。

7.自定義線程

(1)定義一個類,繼承Thread;

(2)重寫__init__ 和 run();

(3)創建線程類對象;

(4)啟動線程。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import time
import threading
class MyThread(threading.Thread):
    def __init__(self,num):
        super().__init__() ###或者是Thread.__init__()
        self.num = num
    def run(self):
        print('線程名稱:', threading.current_thread().getName(), '參數:', self.num, '開始時間:', time.strftime('%Y-%m-%d %H:%M:%S'))
if __name__ == '__main__':
    print('主線程開始:',time.strftime('%Y-%m-%d %H:%M:%S'))
    t1 = MyThread(1)
    t2 = MyThread(2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print('主線程結束:', time.strftime('%Y-%m-%d %H:%M:%S'))

8.線程共享數據與GIL(全局解釋器鎖)

如果是全局變量,則每個線程是共享的;

GIL鎖:可以用籃球比賽的場景來模擬,把籃球場看作是CPU,一場籃球比賽看作是一個線程,如果只有一個籃球場,多場比賽就要排隊進行,類似于一個簡單的單核多線程的程序;如果由多塊籃球場,多場比賽同時進行,就是一個簡單的多核多線程的程序。然而,Python有著特別的規定:每場比賽必須要在裁判的監督之下才允許進行,而裁判只有一個。這樣不管你有幾塊籃球場,同一時間只允許有一個場地進行比賽,其它場地都將被閑置,其它比賽都只能等待。

9.GIL 和 Lock

GIL保證同一時間內一個進程可以有多個線程,但只有一個線程在執行;鎖的目的是為了保護共享的數據,同一時間只能有一個線程來修改共享的數據。

類為threading.Lock

它有兩個基本方法, acquire() 和 release() 。

當狀態為非鎖定時, acquire() 將狀態改為 鎖定 并立即返回。當狀態是鎖定時, acquire() 將阻塞至其他線程調用 release() 將其改為非鎖定狀態,然后 acquire() 調用重置其為鎖定狀態并返回。

release() 只在鎖定狀態下調用; 它將狀態改為非鎖定并立即返回。如果嘗試釋放一個非鎖定的鎖,則會引發 RuntimeError 異常。

Caese 如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from threading import Thread
from threading import Lock
import time
number = 0
def task(lock):
    global number
    lock.acquire() ##持有鎖
    for i in range(100000)      number += 1
    lock.release() ##釋放鎖
if __name__ == '__main__':
    lock=Lock()
    t1 = Thread(target=task,args=(lock,))
    t2 = Thread(target=task,args=(lock,))    t3 = Thread(target=task,args=(lock,))
    t1.start()    t2.start()    t3.start()    t1.join()    t2.join()    t3.join()        print('number:',number)

10.線程的信號量

class threading.Semaphore([values])

values是一個內部計數,values默認是1,如果小于0,則會拋出 ValueError 異常,可以用于控制線程數并發數。

信號量的實現方式:

s=Semaphore(?)

在內部有一個counter計數器,counter的值就是同一時間可以開啟線程的個數。每當我們s.acquire()一次,計數器就進行減1處理,每當我們s.release()一次,計數器就會進行加1處理,當計數器為0的時候,其它的線程就處于等待的狀態。

程序添加一個計數器功能(信號量),限制一個時間點內的線程數量,防止程序崩潰或其它異常。

Case

?
1
2
3
4
5
6
7
8
9
10
11
12
import time
import threading
s=threading.Semaphore(5)    #添加一個計數器
def task():
    s.acquire()    #計數器獲得鎖
    time.sleep(2)    #程序休眠2秒
    print("The task run at ",time.ctime())
    s.release()    #計數器釋放鎖
 
for i in range(40):
    t1=threading.Thread(target=task,args=())    #創建線程
    t1.start()    #啟動線程

也可以使用with操作,替代acquire ()和release(),上面的代碼調整如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
import time
import threading
s=threading.Semaphore(5)    #添加一個計數器
def task():    with s:   ## 類似打開文件的with操作
    ##s.acquire()    #計數器獲得鎖
      time.sleep(2)    #程序休眠2秒
      print("The task run at ",time.ctime())
    ##s.release()    #計數器釋放鎖
 
for i in range(40):
    t1=threading.Thread(target=task,args=())    #創建線程
    t1.start()    #啟動線程

建議使用with。

總結

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注服務器之家的更多內容!

原文鏈接:https://www.cnblogs.com/xuliuzai/p/15488546.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 99热免费在线 | 美女被的视频 | 国产馆精品推荐在线观看 | 国产丰满美女做爰 | 三级无删减高清在线影院 | 99年水嫩漂亮粉嫩在线播放 | 欧美成黑人性猛交xxoo | 色吧五月婷婷 | 日本欧美大码a在线视频播放 | 香蕉久久一区二区不卡无毒影院 | japanesen女同 | 久久婷婷五月综合色丁香花 | 狠狠涩| 欧美整片在线 | 16男男gaygays| 夫妇交换小说 | 亚洲AV无码专区国产乱码网站 | asianfemdom妍妍女王 | 国产玖玖在线观看 | 亚洲美色综合天天久久综合精品 | 免费看欧美一级特黄a大片一 | 国产资源站 | 无码精品AV久久久奶水 | 国产欧美视频在线观看 | 调教校花浣肠开菊 | 午夜AV内射一区二区三区红桃视 | chinesexxxxhd人妖 chinesespanking调教 | 精品成人片深夜 | 成年女人毛片免费观看97 | 国产亚洲综合成人91精品 | 亚洲国产成人在人网站天堂 | 成人快手破解版 | 顶级欧美做受xxx000大乳 | 男同激情视频 | 精品国产综合区久久久久久 | 国产爱啪啪| 精品一区二区高清在线观看 | 免费国产高清精品一区在线 | 久久亚洲精选 | 97色吧| 国产精品亚洲片在线观看麻豆 |