溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

web開發(fā)中的線程是怎樣的

發(fā)布時(shí)間:2021-09-17 09:27:40 來源:億速云 閱讀:89 作者:柒染 欄目:web開發(fā)

web開發(fā)中的線程是怎樣的,很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

中央處理器的調(diào)度單元,簡單點(diǎn)說就是程序中的末端執(zhí)行者,相當(dāng)于小弟的位置。

有人說python中的線程是個(gè)雞肋,這是因?yàn)橛辛薌IL,但是又不是一味的雞肋,畢竟在執(zhí)行io操作時(shí)還是挺管用的,只是在執(zhí)行計(jì)算時(shí)就顯得不盡人意。下面我們來看下線程的具體使用方法:

1.導(dǎo)入線程模塊:

import threading as t

2.線程的用法

tt=t.Thread(group=None,target=None,name=None,args=(),kwargs={},name='',daemon=None) group:線程組,必須是None target:運(yùn)行的函數(shù) args:傳入函數(shù)的參數(shù)元組 kwargs:傳入函數(shù)的參數(shù)字典 name:線程名 daemon:線程是否隨主線程退出而退出(守護(hù)線程)  Thread方法的返回值還有以下方法: tt.start() : 激活線程, tt.getName() : 獲取線程的名稱 tt.setName() :設(shè)置線程的名稱  tt.name : 獲取或設(shè)置線程的名稱 tt.is_alive() :判斷線程是否為激活狀態(tài) tt.isAlive() :判斷線程是否為激活狀態(tài) tt.setDaemon() 設(shè)置為守護(hù)線程(默認(rèn):False) tt.isDaemon() :判斷是否為守護(hù)線程 tt.ident :獲取線程的標(biāo)識(shí)符。只有在調(diào)用了start()方法之后該屬性才有效 tt.join() :逐個(gè)執(zhí)行每個(gè)線程,執(zhí)行完畢后繼續(xù)往下執(zhí)行 tt.run() :自動(dòng)執(zhí)行線程對(duì)象  t的方法也有: t.active_count(): 返回正在運(yùn)行線程的數(shù)量 t.enumerate(): 返回正在運(yùn)行線程的列表 t.current_thread().getName() 獲取當(dāng)前線程的名字 t.TIMEOUT_MAX 設(shè)置t的全局超時(shí)時(shí)間

下面我們來看下吧:

web開發(fā)中的線程是怎樣的

3.創(chuàng)建線程

線程可以使用Thread方法創(chuàng)建,也可以重寫線程類的run方法實(shí)現(xiàn),線程可分為單線程和多線程。

一、使用Thread方法來創(chuàng)建:

1.單線程

def xc():     for y in range(100):         print('運(yùn)行中'+str(y)) tt=t.Thread(target=xc,args=()) #方法加入到線程 tt.start()  #開始線程 tt.join() #等待子線程結(jié)束

2.多線程

def xc(num):     print('運(yùn)行:'+str(num)) c=[] for y in range(100):     tt=t.Thread(target=xc,args=(y,))     tt.start() #開始線程     c.append(tt) #創(chuàng)建列表并添加線程 for x in c:     x.join()  #等待子線程結(jié)束

二、重寫線程的類方法

1.單線程

class Xc(t.Thread): #繼承Thread類     def __init__(self):         super(Xc, self).__init__()      def run(self):  #重寫run方法         for y in range(100):             print('運(yùn)行中'+str(y)) x=Xc()  x.start() #開始線程 x.join()  #等待子線程結(jié)束  也可以這么寫: Xc().run() 和上面的效果是一樣的

2.多線程

class Xc(t.Thread): #繼承Thread類     def __init__(self):         super(Xc, self).__init__()      def run(self,num):  #重寫run方法         print('運(yùn)行:'+str(num)) x=Xc() for y in range(10):     x.run(y) #運(yùn)行

4.線程鎖

為什么要加鎖,看了這個(gè)你就知道了:

web開發(fā)中的線程是怎樣的

多線程在運(yùn)行時(shí)同時(shí)訪問一個(gè)對(duì)象會(huì)產(chǎn)生搶占資源的情況,所以我們必須得束縛它,所以就要給他加一把鎖把他鎖住,這就是同步鎖。要了解鎖,我們得先創(chuàng)建鎖,線程中有兩種鎖:Lock和RLock。

一、Lock

使用方法:

# 獲取鎖 當(dāng)獲取不到鎖時(shí),默認(rèn)進(jìn)入阻塞狀態(tài),設(shè)置超時(shí)時(shí)間,直到獲取到鎖,后才繼續(xù)。非阻塞時(shí),timeout禁止設(shè)置。如果超時(shí)依舊未獲取到鎖,返回False。 Lock.acquire(blocking=True,timeout=1)     #釋放鎖,已上鎖的鎖,會(huì)被設(shè)置為unlocked。如果未上鎖調(diào)用,會(huì)拋出RuntimeError異常。 Lock.release()

互斥鎖,同步數(shù)據(jù),解決多線程的安全問題:

n=10 lock=t.Lock() def xc(num):     lock.acquire()     print('運(yùn)行+:'+str(num+n))     print('運(yùn)行-:'+str(num-n))     lock.release() c=[] for y in range(10):     tt=t.Thread(target=xc,args=(y,))     tt.start()     c.append(tt) for x in c:     x.join()

這樣就顯得有條理了,而且輸出也是先+后-。Lock在一個(gè)線程中多次使用同一資源會(huì)造成死鎖。

死鎖問題:

n=10 lock1=t.Lock() lock2=t.Lock() def xc(num):   lock1.acquire()   print('運(yùn)行+:'+str(num+n))   lock2.acquire()   print('運(yùn)行-:'+str(num-n))   lock2.release()   lock1.release() c=[] for y in range(10):   tt=t.Thread(target=xc,args=(y,))   tt.start()   c.append(tt) for x in c:   x.join()

二、RLock

相比Lock它可以遞歸,支持在同一線程中多次請(qǐng)求同一資源,并允許在同一線程中被多次鎖定,但是acquire和release必須成對(duì)出現(xiàn)。

使用遞歸鎖來解決死鎖:

n=10 lock1=t.RLock() lock2=t.RLock() def xc(num):   lock1.acquire()   print('運(yùn)行+:'+str(num+n))   lock2.acquire()   print('運(yùn)行-:'+str(num-n))   lock2.release()   lock1.release() c=[] for y in range(10):   tt=t.Thread(target=xc,args=(y,))   tt.start()   c.append(tt) for x in c:   x.join()

這時(shí)候,輸出變量就變得僅僅有條了,不在隨意搶占資源。關(guān)于線程鎖,還可以使用with更加方便:

#with上下文管理,鎖對(duì)象支持上下文管理 with lock:   #with表示自動(dòng)打開自動(dòng)釋放鎖   for i in range(10): #鎖定期間,其他人不可以干活     print(i)   #上面的和下面的是等價(jià)的 if lock.acquire(1):#鎖住成功繼續(xù)干活,沒有鎖住成功就一直等待,1代表獨(dú)占   for i in range(10): #鎖定期間,其他線程不可以干活     print(i)   lock.release() #釋放鎖

三、條件鎖

等待通過,Condition(lock=None),可以傳入lock或者Rlock,默認(rèn)Rlock,使用方法:

Condition.acquire(*args)      獲取鎖  Condition.wait(timeout=None)  等待通知,timeout設(shè)置超時(shí)時(shí)間  Condition.notify(num)喚醒至多指定數(shù)目個(gè)數(shù)的等待的線程,沒有等待的線程就沒有任何操作  Condition.notify_all()  喚醒所有等待的線程 或者notifyAll()
def ww(c):   with c:     print('init')     c.wait(timeout=5) #設(shè)置等待超時(shí)時(shí)間5     print('end') def xx(c):   with c:     print('nono')     c.notifyAll() #喚醒所有線程     print('start')     c.notify(1) #喚醒一個(gè)線程     print('21') c=t.Condition() #創(chuàng)建條件 t.Thread(target=ww,args=(c,)).start() t.Thread(target=xx,args=(c,)).start()

這樣就可以在等待的時(shí)候喚醒函數(shù)里喚醒其他函數(shù)里所存在的其他線程了。

5.信號(hào)量

信號(hào)量可以分為有界信號(hào)量和無解信號(hào)量,下面我們來具體看看他們的用法:

一、有界信號(hào)量

它不允許使用release超出初始值的范圍,否則,拋出ValueError異常。

#構(gòu)造方法。value為初始信號(hào)量。value小于0,拋出ValueError異常 b=t.BoundedSemaphore(value=1)    #獲取信號(hào)量時(shí),計(jì)數(shù)器減1,即_value的值減少1。如果_value的值為0會(huì)變成阻塞狀態(tài)。獲取成功返回True BoundedSemaphore.acquire(blocking=True,timeout=None)    #釋放信號(hào)量,計(jì)數(shù)器加1。即_value的值加1,超過初始化值會(huì)拋出異常ValueError。 BoundedSemaphore.release()    #信號(hào)量,當(dāng)前信號(hào)量 BoundedSemaphore._value

web開發(fā)中的線程是怎樣的

可以看到了多了個(gè)release后報(bào)錯(cuò)了。

二、無界信號(hào)量

它不檢查release的上限情況,只是單純的加減計(jì)數(shù)器。

web開發(fā)中的線程是怎樣的

可以看到雖然多了個(gè)release,但是沒有問題,而且信號(hào)量的數(shù)量不受限制。

6.Event

線程間通信,通過線程設(shè)置的信號(hào)標(biāo)志(flag)的False 還是True來進(jìn)行操作,常見方法有:

event.set()      flag設(shè)置為True event.clear()  flag設(shè)置為False event.is_set()  flag是否為True,如果 event.isSet()==False將阻塞線程; 設(shè)置等待flag為True的時(shí)長,None為無限等待。等到返回True,未等到超時(shí)則返回False event.wait(timeout=None)

下面通過一個(gè)例子具體講述:

import time e=t.Event() def ff(num):   while True:     if num<5:       e.clear()   #清空信號(hào)標(biāo)志       print('清空')     if num>=5:       e.wait(timeout=1) #等待信號(hào)標(biāo)志為真       e.set()       print('啟動(dòng)')       if e.isSet(): #如果信號(hào)標(biāo)志為真則清除標(biāo)志         e.clear()         print('停止')     if num==10:       e.wait(timeout=3)       e.clear()       print('退出')       break     num+=1     time.sleep(2) ff(1)

web開發(fā)中的線程是怎樣的

設(shè)置延遲后可以看到效果相當(dāng)明顯,我們讓他干什么事他就干什么事。

7.local

可以為各個(gè)線程創(chuàng)建完全屬于它們自己的變量(線程局部變量),而且它們的值都在當(dāng)前調(diào)用它的線程當(dāng)中,以字典的形式存在。下面我們來看下:

l=t.local()  #創(chuàng)建一個(gè)線程局部變量 def ff(num):   l.x=100  #設(shè)置l變量的x方法的值為100   for y in range(num):     l.x+=3 #改變值   print(str(l.x))  for y in range(10):   t.Thread(target=ff,args=(y,)).start() #開始執(zhí)行線程

那么,可以將變量的x方法設(shè)為全局變量嗎?我們來看下:

web開發(fā)中的線程是怎樣的

可以看出他報(bào)錯(cuò)了,產(chǎn)生錯(cuò)誤的原因是因?yàn)檫@個(gè)類中沒有屬性x,我們可以簡單的理解為局部變量就只接受局部。

8.Timer

設(shè)置定時(shí)計(jì)劃,可以在規(guī)定的時(shí)間內(nèi)反復(fù)執(zhí)行某個(gè)方法。他的使用方法是:

t.Timer(num,func,*args,**kwargs) #在指定時(shí)間內(nèi)再次重啟程序

下面我們來看下:

def f():   print('start')   global t #防止造成線程堆積導(dǎo)致最終程序退出   tt= t.Timer(3, f)   tt.start() f()

這樣就達(dá)到了每三秒執(zhí)行一次f函數(shù)的效果。

看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝您對(duì)億速云的支持。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI