為什么編程的時候要使用進程、線程、協程?使用它們是為了進行多并發編程。那么為什么要進行多并發編程?因為多并發編程可以減少程序運行的時間,讓用戶獲得更好的體驗。
1.進程
概念:操作系統執行程序分配存儲空間的最小單位。一個CPU只能同時處理一個進程。python實現多進程,使用multiprocessing模塊的Process類來創建進程。具體代碼如下:
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,花費%s秒"%(filename,task))
def main():
#記錄開始下載時間
start = time.time()
#創建一個進程,target為進程要執行的方法,args是一個元組,為調用該方法要傳入的參數。
p1 = Process(target=download,args=("python自動化測試.pdf",))
#啟動進程
p1.start()
p2 = Process(target=download,args=("測試技巧.pdf",))
p2.start()
#執行進程并等待進程執行結束
p1.join()
p2.join()
#記錄下載完成時間
end = time.time()
#輸出下載總耗時
print("下載總耗時%.2f秒"%(end-start))
if __name__ == "__main__":
main()
輸出結果如下:
使用多進程的編程的好處是可以大大提高代碼的執行效率,但是多進程存在一個問題,進程之前的通信比較復雜,實現起來會占用較大的資源,此時我們引入線程的來解決這個問題。
2.線程
一個進程可以包含多個線程,同一進程中的每個線程的信息是可以進行共享的。python使用threading模塊的Thread類來創建新的線程。python的類是可以繼承的,我們創建類時可以繼承Thread類。具體代碼如下:
from threading import Thread
from random import randint
import time
#創建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,花費%s秒"%(self._filename,task))
def close(self):
print("3sdf%s"%self._filename)
def main():
start = time.time()
t1 = Download("python自動化測試.pdf")
#執行t1.start時,會運行run方法
t1.start()
t2 = Download("測試技巧.pdf")
t2.start()
t1.join()
t2.join()
end = time.time()
print("下載完成,共耗時%.2f"%(end-start))
if __name__ == "__main__":
main()
輸出結果如下:
在進行出入庫操作時,多線程并發時,會導致數據丟失問題。我們寫一段代碼,庫存值為100,啟動50個線程同時進行入庫操作,所有線程入庫結束后。理論上最終的庫存值為150。具體代碼如下:
from threading import Thread
from random import randint
import time
class Repertory(object):
"創建倉庫類"
def __init__(self):
#初始化倉庫數量
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):
#返回倉庫庫存數量
return self._initialize_number
class AddNumberThread(Thread):
def __init__(self, repertory, number):
"""
:param repertory: 倉庫對象
:param number: 新增庫存數量
"""
super().__init__()
self._repertory = repertory
self._number = number
def run(self):
self._repertory.add_number(number=self._number)
def main():
repertory = Repertory()
threads = []
#創建50個線程進行入庫操作
for _ in range(50):
t = AddNumberThread(repertory=repertory,number=1)
threads.append(t)
t.start()
#等待所有線程入庫結束
for thread in threads:
thread.join()
#打印最終的庫存數
print("倉庫庫存數%s"%repertory.number)
if __name__ == "__main__":
main()
輸出結果如下:
運行結果與我們想象中的完全不一樣,因為大部分線程啟動的時候,self._initialize_number都等于100,要解決這個問題,就需要用到線程鎖。在代碼中加入鎖,修改后的代碼如下:
from threading import Thread, Lock
import time
class Repertory(object):
"創建倉庫類"
def __init__(self):
#初始化倉庫數量
self._initialize_number = 100
#定義鎖
self._lock = Lock()
def add_number(self,number):
#拿到鎖才能執行下面代碼
self._lock.acquire()
try:
#入庫操作
new_number = number+self._initialize_number
#模擬入庫時間
time.sleep(0.01)
#更新倉庫庫存
self._initialize_number = new_number
finally:
#代碼執行完成后,釋放鎖
self._lock.release()
@property
def number(self):
#返回倉庫庫存數量
return self._initialize_number
class AddNumberThread(Thread):
def __init__(self, repertory, number):
"""
:param repertory: 倉庫對象
:param number: 新增庫存數量
"""
super().__init__()
self._repertory = repertory
self._number = number
def run(self):
self._repertory.add_number(number=self._number)
def main():
repertory = Repertory()
threads = []
#創建50個線程進行入庫操作
for _ in range(50):
t = AddNumberThread(repertory=repertory,number=1)
threads.append(t)
t.start()
#等待所有線程入庫結束
for thread in threads:
thread.join()
#打印最終的庫存數
print("倉庫庫存數%s"%repertory.number)
if __name__ == "__main__":
main()
輸入結果如下:
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
