進(jìn)程:正在運(yùn)行的一個(gè)程序府适,每個(gè)進(jìn)程相互獨(dú)立唯绍,并且運(yùn)行在其專用且受保護(hù)的內(nèi)存空間里面的。
線程:一個(gè)進(jìn)程要想執(zhí)行任務(wù)偿荷,必須得有線程(每個(gè)進(jìn)程至少有一個(gè)線程)窘游,一個(gè)進(jìn)程所有任務(wù)都在線程中執(zhí)行。
主線程:每個(gè)進(jìn)程默認(rèn)有一個(gè)線程跳纳,這個(gè)線程叫主線程忍饰。默認(rèn)情況下,所有的代碼都是在主線程中執(zhí)行的寺庄。
子線程:一個(gè)進(jìn)程可以有多個(gè)線程艾蓝。除了主線程以外,其他線程需要手動(dòng)添加斗塘。
多線程原理:
同一時(shí)間赢织,CPU只能處理一條線程,只有1條線程在工作馍盟。多線程并發(fā)執(zhí)行于置,其實(shí)就是CPU快速的在多線程之間調(diào)度(切換),當(dāng)CPU調(diào)度線程的時(shí)間足夠快贞岭,就造成了多線程并發(fā)執(zhí)行的假象八毯。
使用情況:
讓多個(gè)任務(wù)同時(shí)執(zhí)行搓侄。
補(bǔ)充:
a、打印當(dāng)前時(shí)間
import datetime
datetime.datetime.now()
b宪彩、延時(shí)
import time
time.sleep(s)
方式一
1休讳、模塊
python中內(nèi)置模塊 threading,用來支持多線程尿孔。Thread類的對(duì)象就是線程對(duì)象,需要線程的時(shí)候筹麸,就創(chuàng)建這個(gè)類或者這個(gè)類的子類對(duì)象活合。
import threading
獲取當(dāng)前線程對(duì)象 >>> 用于測試
threading.current_thread()
2、創(chuàng)建子線程對(duì)象
t1 = threading.Thread(target=download, args=('終結(jié)者',))
"""
target:需要在子線程中調(diào)用的函數(shù)的函數(shù)名物赶,子線程中執(zhí)行的任務(wù)就是函數(shù)里面的代碼白指。
args:函數(shù)對(duì)應(yīng)的參數(shù)值(元組)
返回值:創(chuàng)建好的線程對(duì)象
"""
3、執(zhí)行
t1.start()
效果:
import threading
import datetime
import time
#模擬下載兩個(gè)電影
def download(file):
print('開始下載:', datetime.datetime.now())
# 線程阻塞2s
time.sleep(2)
print(file+'下載結(jié)束',datetime.datetime.now())
print(threading.current_thread())
t1 = threading.Thread(target=download, args=('終結(jié)者2',))
t1.start()
t2 = threading.Thread(target=download, args=('沉默的羔羊',))
t2.start()
download('終結(jié)者1')
開始下載: 2018-09-13 11:08:56.927703
開始下載: 2018-09-13 11:08:56.928703
開始下載: 2018-09-13 11:08:56.928703
終結(jié)者2下載結(jié)束 2018-09-13 11:08:58.927818
<Thread(Thread-1, started 2324)>
沉默的羔羊下載結(jié)束 2018-09-13 11:08:58.928818
<Thread(Thread-2, started 5908)>
終結(jié)者1下載結(jié)束 2018-09-13 11:08:58.928818
<_MainThread(MainThread, started 5852)>
方式二---面向?qū)ο蟮亩嗑€程技術(shù)(重點(diǎn))
1酵紫、聲明一個(gè)類繼承自Thread類
2告嘲、重寫run方法,將需要在子線程中執(zhí)行的任務(wù)放到run方法中
3奖地、在需要子線程的位置去創(chuàng)建這個(gè)類的對(duì)象橄唬,然后調(diào)用start 方法去執(zhí)行run中的任務(wù)。
from threading import Thread
import datetime
import time
class DownLoadThread(Thread):
def __init__(self, file):
super().__init__()
self.file = file
def run(self):
print('開始下載:<%s> 時(shí)間:%s'%(self.file,datetime.datetime.now()))
time.sleep(5)
print('下載結(jié)束:<%s>参歹! 時(shí)間:%s'%(self.file,datetime.datetime.now()))
print('===========')
t1 = DownLoadThread('沉默的羔羊')
t1.start()
print('+++++++++++')
結(jié)果:
===========
開始下載:<沉默的羔羊> 時(shí)間:2018-09-13 11:26:42.730664
+++++++++++
下載結(jié)束:<沉默的羔羊>仰楚! 時(shí)間:2018-09-13 11:26:47.730950
三、join方法的使用
如果希望某個(gè)線程結(jié)束后才執(zhí)行某個(gè)操作犬庇,就用線程對(duì)象調(diào)用 join()
start()會(huì)自動(dòng)調(diào)用run()
from threading import Thread
import time
import datetime
import random
class DownLoadThread(Thread):
def __init__(self, file):
super().__init__()
self.file = file
def run(self):
print(self.file+' 開始下載', datetime.datetime.now())
time.sleep(random.randint(5,15))
print(self.file+' 下載結(jié)束', datetime.datetime.now())
t1 = DownLoadThread('美麗人生')
t2 = DownLoadThread('怦然心動(dòng)')
start = time.time()
t1.start()
t2.start()
#t1,t2都結(jié)束才執(zhí)行
t1.join() #后面的代碼在t1對(duì)應(yīng)的線程結(jié)束后才執(zhí)行
t2.join() #后面的代碼在t1對(duì)應(yīng)的線程結(jié)束后才執(zhí)行
end = time.time()
print(end - start)
結(jié)果:
美麗人生 開始下載 2018-09-13 13:36:42.334387
怦然心動(dòng) 開始下載 2018-09-13 13:36:42.334387
美麗人生 下載結(jié)束 2018-09-13 13:36:49.334787
怦然心動(dòng) 下載結(jié)束 2018-09-13 13:36:50.336844
8.00445818901062
四僧界、多線程的數(shù)據(jù)混亂問題
盡量避免多個(gè)線程對(duì)同一個(gè)數(shù)據(jù)進(jìn)行操作
解決方法:對(duì)相關(guān)代碼加鎖,讓同一時(shí)間只有能有一個(gè)線程進(jìn)行操作臭挽,釋放后捂襟,才能讓其它線程操作
鎖: 同步鎖(RLock) 和 互斥鎖(Lock)-- 了解
from threading import Lock
1、創(chuàng)建鎖對(duì)象
self.lock = Lock()
# 一般寫在__init__方法中
2欢峰、加鎖
self.lock.acquire()
# 線程操作前
3葬荷、解鎖
self.lock.release()
# 線程操作后
實(shí)例:
"""__author__=Deathfeeling"""
import time
from threading import Thread, Lock
class Account():
"""賬號(hào)類"""
def __init__(self, balance):
self.balance = balance
# 創(chuàng)建鎖對(duì)象
self.lock = Lock()
def save_money(self, amount):
"""存錢"""
print('開始存錢')
# 加鎖
self.lock.acquire()
old_amount = self.balance
time.sleep(2)
self.balance = old_amount + amount
print('存錢成功!最新余額是:',self.balance)
# 解鎖
self.lock.release()
def get_money(self, amount):
"""取錢"""
self.lock.acquire()
print('開始取錢')
old_amount = self.balance
if old_amount < amount:
print('余額不足')
return
time.sleep(2)
self.balance = old_amount - amount
print('取錢成功赤赊!最新余額是:', self.balance)
self.lock.release()
def show_balance(self):
print('當(dāng)前余額:', self.balance)
account = Account(1000)
# account.save_money(200)
# account.get_money(100)
# account.show_balance()
t1 = Thread(target=account.save_money, args=(200,))
t2 = Thread(target=account.save_money, args=(300,))
t1.start()
t2.start()
結(jié)果:
開始存錢
開始存錢
存錢成功闯狱!最新余額是: 1200
存錢成功!最新余額是: 1500