1 進(jìn)程和線程
進(jìn)程:進(jìn)程就是操作系統(tǒng)中執(zhí)行的一個(gè)程序,操作系統(tǒng)以進(jìn)程為單位分配存儲(chǔ)空間,每個(gè)進(jìn)程都有自己的地址空間、數(shù)據(jù)棧以及其他用于跟蹤進(jìn)程執(zhí)行的輔助數(shù)據(jù)
線程:一個(gè)進(jìn)程還可以擁有多個(gè)并發(fā)的執(zhí)行線索,簡(jiǎn)單的說(shuō)就是擁有多個(gè)可以獲得CPU調(diào)度的執(zhí)行單元,這就是所謂的線程。每個(gè)進(jìn)程默認(rèn)都有一個(gè)線程,這個(gè)線程叫主線程;其他的線程都叫子線程
1.1 直接調(diào)用threading模塊進(jìn)行多線程操作
import time
from datetime import datetime
import threading
def download(film_name):
print('開(kāi)始下載:%s' % film_name,datetime.now())
time.sleep(5)
print('%s下載完成' % film_name,datetime.now())
# 1、單線程下載兩個(gè)電影
# # 在一個(gè)線程中下載兩個(gè)電影:時(shí)間是兩個(gè)電影下載的綜合
# download('123')
# download('456')
# 2、線程模塊
# 1)current_thread函數(shù) -- 獲取當(dāng)前線程
print(threading.current_thread())
# 2)Thread類(lèi)
# Thread類(lèi)的對(duì)象就是線程,所以需要子線程就創(chuàng)建這個(gè)類(lèi)的對(duì)象
# Thread(target,args,kwargs)
# target -- 函數(shù),需要在當(dāng)前創(chuàng)建的子線程中取調(diào)用的函數(shù)
# a.創(chuàng)建線程對(duì)象 -- 調(diào)用target中的函數(shù)需要的實(shí)參列表
t1 = threading.Thread(target=download, args=('123',))
t2 = threading.Thread(target=download, args=('456',))
# b.開(kāi)始執(zhí)行子線程中的任務(wù):線程對(duì)象.start()
# 通過(guò)start方法,在子線程中去調(diào)用target對(duì)應(yīng)的函數(shù)
t1.start()
t2.start()
1.2 通過(guò)創(chuàng)建類(lèi)進(jìn)行多線程操作
import random
import time
from datetime import datetime
import threading
# 1、創(chuàng)建自己的線程類(lèi)
'''
1)聲明一個(gè)類(lèi)繼承Thread
2)實(shí)現(xiàn)潤(rùn)方法,這個(gè)方法中的任務(wù)就是需要在子線程中執(zhí)行的任務(wù)
注意:一個(gè)進(jìn)程中如果有多個(gè)線程,程序會(huì)在所有的線程都結(jié)束時(shí)才結(jié)束
發(fā)生異常崩潰其實(shí)崩潰的是線程
'''
class DownloadThread(threading.Thread):
def __init__(self, film_name):
super().__init__()
self.film_name =film_name
def run(self):
print('開(kāi)始下載:%s' % self.film_name,datetime.now())
time.sleep(random.randint(5,10))
print('%s下載完成' % self.film_name,datetime.now())
# 3、用子類(lèi)直接創(chuàng)建線程對(duì)象
t1 = DownloadThread('123')
t2 = DownloadThread('456')
#4、通過(guò)start去執(zhí)行子線的中的任務(wù)
t1.start()
t2.start()
# t1.run() 不能直接調(diào)用run方法,因?yàn)檫@樣不會(huì)再子線程中執(zhí)行任務(wù)
1.3 join
如果希望某個(gè)人物是在某個(gè)線程結(jié)束后才執(zhí)行,那就將這個(gè)人物的代碼放在對(duì)應(yīng)線程對(duì)象調(diào)用join方法的后面.
from threading import *
import time
from random import randint
class DownloadThread(Thread):
def __init__(self, name):
super().__init__()
self.name = name
self.time = 0
def run(self):
self.time = randint(5, 10)
print('開(kāi)始下載%s' % self.name)
time.sleep(self.time)
print('%s下載結(jié)束,用時(shí)%s' % (self.name, self.time))
start = time.time()
t1 = DownloadThread('123')
t2 = DownloadThread('456')
t1.start()
t2.start()
t1.join()
t2.join()
end = time.time()
print('下載結(jié)束,總共用時(shí)%s' % (end-start))
1.4 鎖的使用
1.問(wèn)題
當(dāng)多個(gè)線程同時(shí)對(duì)一個(gè)數(shù)據(jù)進(jìn)行讀寫(xiě)操作,可能會(huì)出現(xiàn)一個(gè)線程剛把數(shù)據(jù)讀出來(lái)還沒(méi)來(lái)得及寫(xiě)進(jìn)去,另一個(gè)線程進(jìn)行讀操作而出現(xiàn)的數(shù)據(jù)安全問(wèn)題
2.解決 -- 加鎖
1)保證每個(gè)數(shù)據(jù)對(duì)應(yīng)一個(gè)鎖對(duì)象
2)操作數(shù)據(jù)前加鎖,數(shù)據(jù)操作完成后釋放鎖