python自動化測試學習筆記-8多線程


線程模塊

python的多線程只能利用cpu的一個核心,一個核心同時只能運行一個任務那么為什么你使用多線程的時候,它的確是比單線程快
答:如果是一個計算為主的程序(專業一點稱為CPU密集型程序),這一點確實是比較吃虧的,每個線程運行一遍,就相當於單線程再跑,甚至比單線程還要慢——CPU切換線程的上下文也是要有開銷的。
但是,如果是一個磁盤或網絡為主的程序(IO密集型)就不同了。一個線程處在IO等待的時候,另一個線程還可以在CPU里面跑,有時候CPU閑着沒事干,所有的線程都在等着IO,這時候他們就是同時的了,
而單線程的話此時還是在一個一個等待的。我們都知道IO的速度比起CPU來是慢到令人發指的,python的多線程就在這時候發揮作用了。比方說多線程網絡傳輸,多線程往不同的目錄寫文件,等等。

Python通過兩個標准庫thread和threading提供對線程的支持。thread提供了低級別的、原始的線程以及一個簡單的鎖。

threading 模塊提供的其他方法:

  • threading.currentThread(): 返回當前的線程變量。
  • threading.enumerate(): 返回一個包含正在運行的線程的list。正在運行指線程啟動后、結束前,不包括啟動前和終止后的線程。
  • threading.activeCount(): 返回正在運行的線程數量,與len(threading.enumerate())有相同的結果。

除了使用方法外,線程模塊同樣提供了Thread類來處理線程,Thread類提供了以下方法:

  • run(): 用以表示線程活動的方法。
  • start():啟動線程活動。
  • join([time]): 等待至線程中止。這阻塞調用線程直至線程的join() 方法被調用中止-正常退出或者拋出未處理的異常-或者是可選的超時發生。
  • isAlive(): 返回線程是否活動的。
  • getName(): 返回線程名。
  • setName(): 設置線程名。

定義一個線程:

def learn(name,age):
print('my name is %s ,%s years old ,i like swim '%(name,age))
#定義一個線程,指定運行哪個程序,一個線程后args后邊跟逗號
t=threading.Thread(target=learn,args=('wang',34))
t.start()

如果要啟動多個線程,可以使用循環實現:

users=[
['wang',34,'swim'],
['li',23,'travel'],
['zhao',14,'reading']

]
def learn(name,age,skill):
time.sleep(10)
print('my name is %s ,%s years old ,i like %s '%(name,age,skill))
#定義一個線程,指定運行哪個程序,一個線程后args后邊跟逗號
for user in users:
t=threading.Thread(target=learn,args=(user[0],user[1],user[2]))
t.start()

print('主線程結束')

查看執行結果:

主線程結束
my name is wang ,34 years old ,i like swim
my name is li ,23 years old ,i like travel
my name is zhao ,14 years old ,i like reading

Python中,默認情況下,如果不加join語句,那么主線程不會等到當前線程結束才結束,但卻不會立即殺死該線程

我們看到上邊的代碼,執行后,先結束了主線程,但子線程還在執行中,10秒以后子線程結束,為了避免這種情況,我們可以使用join來是子線程進行等待,join是阻塞當前線程,即使得在當前線程結束時,不會退出。

users=[
['wang',34,'swim'],
['li',23,'travel'],
['zhao',14,'reading']

]
def learn(name,age,skill):
time.sleep(5)
print('my name is %s ,%s years old ,i like %s '%(name,age,skill))
#定義一個線程,指定運行哪個程序,一個線程后args后邊跟逗號
threads=[]
for user in users:
t=threading.Thread(target=learn,args=(user[0],user[1],user[2]))
t.start()
threads.append(t)
for t in threads:
t.join()#主線程等待子線程結束

print('主線程結束')

執行查看結果:

my name is li ,23 years old ,i like travel
my name is zhao ,14 years old ,i like reading
my name is wang ,34 years old ,i like swim
主線程結束

守護線程:setDaemon(True),設置之后如果不加join語句,當主線程結束后,會殺死子線程

users=[
['wang',34,'swim'],
['li',23,'travel'],
['zhao',14,'reading']

]
def learn(name,age,skill):
time.sleep(5)
print('my name is %s ,%s years old ,i like %s '%(name,age,skill))
#定義一個線程,指定運行哪個程序,一個線程后args后邊跟逗號
threads=[]
for user in users:
t=threading.Thread(target=learn,args=(user[0],user[1],user[2]))
t.setDaemon(True)
t.start()

print('主線程結束')

執行查看結果:
主線程結束

我們看到,不加setDaemon(True)的時候,主線程結束之后,子線程沒有立即結束,是在執行完之后結束的。添加setDaemon(True),主線程結束后子線程立即結束。

線程池:我們上面用到的循環的方式開啟了多個線程,python中可以使用第三方的包threadpool線程池包,實現處理線程問題

安裝:pip install threadpool

    (1)引入threadpool模塊

    (2)定義線程函數
    (3)創建線程 池threadpool.ThreadPool()
    (4)創建需要線程池處理的任務即threadpool.makeRequests()
    (5)將創建的多個任務put到線程池中,threadpool.putRequest
    (6)等到所有任務處理完畢theadpool.wait()
import threadpool
#定義線程函數
def say(num):
print(num)

#創建線程池
pool=threadpool.ThreadPool(3)
#生成線程池要執行的東西,makeRequests,傳入數量,自動找出每個線程要執行的數據
reqs=threadpool.makeRequests(say,list(range(11)))
#創建多個任務put到線程池中
for req in reqs:
pool.putRequest(req)
pool.wait()

執行:

0
1
2
3
4
5
6
7
8
9
10

現在我們可以來封裝一個線程池了:


import threadpool

class MyPool(object):
def __init__(self,func,poolsize=10,data=None):
self.func=func
self.poolsize=poolsize
self.data=data
def pool(self):
pool=threadpool.ThreadPool(self.poolsize)
reqs=threadpool.makeRequests(self.func,self.data)
[pool.putRequest(req) for req in reqs]
pool.wait()

我們定義一個簡單的函數來調用一下:

def say(num):
print(num)

my=MyPool(say,2,[1,2,3,4,5])
my.pool()

 


免責聲明!

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



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