為什么編程的時候要使用進(jìn)程、線程、協(xié)程?使用它們是為了進(jìn)行多并發(fā)編程。那么為什么要進(jìn)行多并發(fā)編程?因?yàn)槎嗖l(fā)編程可以減少程序運(yùn)行的時間,讓用戶獲得更好的體驗(yàn)。
1.進(jìn)程
概念:操作系統(tǒng)執(zhí)行程序分配存儲空間的最小單位。一個CPU只能同時處理一個進(jìn)程。python實(shí)現(xiàn)多進(jìn)程,使用multiprocessing模塊的Process類來創(chuàng)建進(jìn)程。具體代碼如下:
from multiprocessing import Process
from os import getpid
import time
from random import randint
def download(filename):
"""
定義一個下載文件的方法
:param filename:要下載的文件名
:return:
"""
task = randint(8, 15)
time.sleep(task)
print("下載文件:%s,花費(fèi)%s秒"%(filename,task))
def main():
#記錄開始下載時間
start = time.time()
#創(chuàng)建一個進(jìn)程,target為進(jìn)程要執(zhí)行的方法,args是一個元組,為調(diào)用該方法要傳入的參數(shù)。
p1 = Process(target=download,args=("python自動化測試.pdf",))
#啟動進(jìn)程
p1.start()
p2 = Process(target=download,args=("測試技巧.pdf",))
p2.start()
#執(zhí)行進(jìn)程并等待進(jìn)程執(zhí)行結(jié)束
p1.join()
p2.join()
#記錄下載完成時間
end = time.time()
#輸出下載總耗時
print("下載總耗時%.2f秒"%(end-start))
if __name__ == "__main__":
main()
輸出結(jié)果如下:
使用多進(jìn)程的編程的好處是可以大大提高代碼的執(zhí)行效率,但是多進(jìn)程存在一個問題,進(jìn)程之前的通信比較復(fù)雜,實(shí)現(xiàn)起來會占用較大的資源,此時我們引入線程的來解決這個問題。
2.線程
一個進(jìn)程可以包含多個線程,同一進(jìn)程中的每個線程的信息是可以進(jìn)行共享的。python使用threading模塊的Thread類來創(chuàng)建新的線程。python的類是可以繼承的,我們創(chuàng)建類時可以繼承Thread類。具體代碼如下:
from threading import Thread
from random import randint
import time
#創(chuàng)建Download類,繼承Thread類
class Download(Thread):
def __init__(self, filename):
super().__init__()
self._filename = filename
def run(self):
task = randint(8, 13)
time.sleep(task)
print("下載文件:%s,花費(fèi)%s秒"%(self._filename,task))
def close(self):
print("3sdf%s"%self._filename)
def main():
start = time.time()
t1 = Download("python自動化測試.pdf")
#執(zhí)行t1.start時,會運(yùn)行run方法
t1.start()
t2 = Download("測試技巧.pdf")
t2.start()
t1.join()
t2.join()
end = time.time()
print("下載完成,共耗時%.2f"%(end-start))
if __name__ == "__main__":
main()
輸出結(jié)果如下:
在進(jìn)行出入庫操作時,多線程并發(fā)時,會導(dǎo)致數(shù)據(jù)丟失問題。我們寫一段代碼,庫存值為100,啟動50個線程同時進(jìn)行入庫操作,所有線程入庫結(jié)束后。理論上最終的庫存值為150。具體代碼如下:
from threading import Thread
from random import randint
import time
class Repertory(object):
"創(chuàng)建倉庫類"
def __init__(self):
#初始化倉庫數(shù)量
self._initialize_number = 100
def add_number(self,number):
#入庫操作
new_number = number+self._initialize_number
#模擬入庫時間
time.sleep(0.01)
#更新倉庫庫存
self._initialize_number = new_number
@property
def number(self):
#返回倉庫庫存數(shù)量
return self._initialize_number
class AddNumberThread(Thread):
def __init__(self, repertory, number):
"""
:param repertory: 倉庫對象
:param number: 新增庫存數(shù)量
"""
super().__init__()
self._repertory = repertory
self._number = number
def run(self):
self._repertory.add_number(number=self._number)
def main():
repertory = Repertory()
threads = []
#創(chuàng)建50個線程進(jìn)行入庫操作
for _ in range(50):
t = AddNumberThread(repertory=repertory,number=1)
threads.append(t)
t.start()
#等待所有線程入庫結(jié)束
for thread in threads:
thread.join()
#打印最終的庫存數(shù)
print("倉庫庫存數(shù)%s"%repertory.number)
if __name__ == "__main__":
main()
輸出結(jié)果如下:
運(yùn)行結(jié)果與我們想象中的完全不一樣,因?yàn)榇蟛糠志€程啟動的時候,self._initialize_number都等于100,要解決這個問題,就需要用到線程鎖。在代碼中加入鎖,修改后的代碼如下:
from threading import Thread, Lock
import time
class Repertory(object):
"創(chuàng)建倉庫類"
def __init__(self):
#初始化倉庫數(shù)量
self._initialize_number = 100
#定義鎖
self._lock = Lock()
def add_number(self,number):
#拿到鎖才能執(zhí)行下面代碼
self._lock.acquire()
try:
#入庫操作
new_number = number+self._initialize_number
#模擬入庫時間
time.sleep(0.01)
#更新倉庫庫存
self._initialize_number = new_number
finally:
#代碼執(zhí)行完成后,釋放鎖
self._lock.release()
@property
def number(self):
#返回倉庫庫存數(shù)量
return self._initialize_number
class AddNumberThread(Thread):
def __init__(self, repertory, number):
"""
:param repertory: 倉庫對象
:param number: 新增庫存數(shù)量
"""
super().__init__()
self._repertory = repertory
self._number = number
def run(self):
self._repertory.add_number(number=self._number)
def main():
repertory = Repertory()
threads = []
#創(chuàng)建50個線程進(jìn)行入庫操作
for _ in range(50):
t = AddNumberThread(repertory=repertory,number=1)
threads.append(t)
t.start()
#等待所有線程入庫結(jié)束
for thread in threads:
thread.join()
#打印最終的庫存數(shù)
print("倉庫庫存數(shù)%s"%repertory.number)
if __name__ == "__main__":
main()
輸入結(jié)果如下:
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

