進(jìn)程
1.什么是進(jìn)程:在系統(tǒng)中正在運行的一個應(yīng)用程序
2.每個進(jìn)程之間是獨立的,每個進(jìn)程均運行在其專用且受保護(hù)的內(nèi)存空間內(nèi)
3.什么是線程:1個進(jìn)程要想執(zhí)行任務(wù),必須得有線程(每一個進(jìn)程至少要有一條線程);一個進(jìn)程的所有任務(wù)都在線程中執(zhí)行
4.線程的串行:一個線程中任務(wù)的執(zhí)行是串行的
5.什么是多線程:1個進(jìn)程中可以開啟多條線程,每條線程可以并行執(zhí)行不同的任務(wù)
*進(jìn)程->車間,線程->車間工人
多線程技術(shù)可以提高程序的執(zhí)行效率
6.多線程原理:同一時間,cpu只能處理1條線程,只有1條線程在工作(執(zhí)行),多線程并發(fā)執(zhí)行,其實是cpu快速的在多條線程之間調(diào)度,如果cpu調(diào)度線程的時間足夠快,就造成了多線程并發(fā)執(zhí)行的假象.
2.多線程基礎(chǔ)
1.主線程:
每個進(jìn)程默認(rèn)都會有一個線程,這個線程我們一般都叫它主線程
默認(rèn)情況下,所有的代碼都是在主線程中執(zhí)行.
2.子線程
一個進(jìn)程中可以有多個線程.除了主線程以外,其他的線程需要手動的添加
3.threading是python中的一個內(nèi)置模塊,用來支持多線程
a.Thread類
Thread類的對象就是線程對象,需要線程的時候,就創(chuàng)這個類或者這個類的子類對象
b.threading.currentThread()-->用來獲取當(dāng)前線程對象
import threading
import datetime
import time
# 下載兩個電影
def download(file):
print('開始下載:'+file,datetime.datetime.now())
# 讓線程阻塞5秒
time.sleep(5)
print(file+'下載結(jié)束:',datetime.datetime.now())
if __name__ == '__main__':
print('主線程中的代碼')
print(threading.currentThread())
#1.在主線程中下載兩個電影:總共耗時20秒
# download('多來a夢')
# download('沉默的羔羊')
# 2.在兩個子線程中去下載兩個電影:總共耗時10秒
"""
Thread(target=)
target:需要在子線程中調(diào)用的函數(shù)的函數(shù)名
args:函數(shù)的實參
返回值:創(chuàng)建好的線程對象
"""
t1 = threading.Thread(target=download,args=('多來a夢',))
# 開始執(zhí)行t1對應(yīng)的線程中的任務(wù)
t1.start()
t2 = threading.Thread(target=download, args=('多來a夢',))
# 想要在子線程中執(zhí)行任務(wù),必須通過線程對象調(diào)用start方法才行 v
t2.start()
print('==============')
輸出結(jié)果:
主線程中的代碼
<_MainThread(MainThread, started 3768)>
開始下載:多來a夢 2018-09-13 16:40:05.539924
開始下載:多來a夢 2018-09-13 16:40:05.539924
==============
多來a夢下載結(jié)束: 2018-09-13 16:40:10.540210
多來a夢下載結(jié)束: 2018-09-13 16:40:10.541210
3.面向?qū)ο蟮亩嗑€程技術(shù)
from threading import Thread
import datetime
import time
from random import randint
'''
面向?qū)ο髮崿F(xiàn)多線程技術(shù)
1.聲明一個類繼承自Thread類
2.重寫run方法,將需要在子線程中執(zhí)行的任務(wù)放到run方法中
3.在需要子線程的位置去創(chuàng)建這個類的對象,然后用對象調(diào)用start方法去執(zhí)行run中的任務(wù)
'''
#注意:繼承的時候,可以繼承自己寫的類,也可以繼承系統(tǒng)的類或者別人寫好的類
class Download(Thread):
"""下載線程類"""
def __init__(self,file):
super().__init__()
self.file = file
def run(self):
print(self.file+'開始下載:',datetime.datetime.now())
time.sleep(randint(5,10))
print(self.file+'下載結(jié)束:',datetime.datetime.now())
if __name__ == '__main__':
print('===========')
t1 = Download('沉默的羔羊')
t1.start()
t2 = Download('恐怖游輪')
t2.start()
print('+++++++++++')
輸出結(jié)果:
===========
沉默的羔羊開始下載: 2018-09-13 16:41:25.749512
恐怖游輪開始下載: 2018-09-13 16:41:25.749512
+++++++++++
恐怖游輪下載結(jié)束: 2018-09-13 16:41:33.749969
沉默的羔羊下載結(jié)束: 2018-09-13 16:41:34.750026
4.join的方法使用
from threading import Thread
import time
from datetime import datetime
from random import randint
# 在兩個子線程中下載兩個電影,在主線程中去統(tǒng)計兩個電影下載的時間
"""
如果希望某個線程結(jié)束后才執(zhí)行某個操作,就用那個線程調(diào)用join方法
"""
class Download(Thread):
def __init__(self,file):
super().__init__()
self.file = file
def run(self):
print(self.file+'開始下載:',datetime.now())
time.sleep(randint(5,15))
print(self.file+'下載結(jié)束',datetime.now())
if __name__ == '__main__':
t1 = Download('美麗人生')
t2 = Download('怦然心動')
start = time.time()
time1 = t1.start()
time2 = t2.start()
#系統(tǒng)t1和t2中的代碼都結(jié)束后才執(zhí)行下面的代碼
t1.join() #這句代碼后面的代碼在t1對應(yīng)的線程結(jié)束后才執(zhí)行
t2.join()
end = time.time()
print(end-start)
輸出結(jié)果:
美麗人生開始下載: 2018-09-13 16:42:35.958527
怦然心動開始下載: 2018-09-13 16:42:35.959527
怦然心動下載結(jié)束 2018-09-13 16:42:46.960157
美麗人生下載結(jié)束 2018-09-13 16:42:46.960157
11.004629373550415
5.線程間數(shù)據(jù)共享
模擬多個人對同一賬號進(jìn)行操作
同步鎖(RLock)和互斥鎖(Lock)
import time
from threading import Thread,Lock,RLock
class Account:
"""賬號類"""
def __init__(self,balance):
#余額
self.balance = balance
#創(chuàng)建鎖對象
self.lock = Lock()
# 存錢的過程:讀出原來的余額,確定錢的一系列操作,將原來的余額加上存的數(shù)額產(chǎn)生最新的余額再保存
def save_money(self,amount):
# 存錢
# 獲取原來的余額
print('開始存錢')
self.lock.acquire()
old_amount = self.balance
# 模擬時間消耗
time.sleep(5)
self.balance = old_amount + amount
print('存錢成功!,最新余額:',self.balance)
#解鎖
self.lock.release()
def get_money(self,amount):
'''取錢'''
print('開始取錢')
self.lock.acquire()
old_amount = self.balance
if old_amount < amount:
print('余額不足!')
return
time.sleep(5)
self.balance = old_amount - amount
print('取錢成功,最新余額是:',self.balance)
self.lock.release()
def show_balance(self):
print('當(dāng)前余額:',self.balance)
if __name__ == '__main__':
account = Account(1000)
# account.save_money(200)
# account.get_money(100)
# account.show_balance()
"""
當(dāng)多個線程同時對一個數(shù)據(jù)進(jìn)行操作的時候,可能會出現(xiàn)數(shù)據(jù)混亂的問題
"""
t1 = Thread(target=account.save_money,args=(200,))
t2 = Thread(target=account.save_money,args=(1300,))
t3 = Thread(target=account.get_money,args=(800,))
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
account.show_balance()
輸出結(jié)果:
開始存錢
開始存錢
開始取錢
存錢成功!,最新余額: 1200
存錢成功!,最新余額: 2500
取錢成功,最新余額是: 1700
當(dāng)前余額: 1700