1. 多線程
線程:是進(jìn)程中一個(gè)“單一的連續(xù)控制流程”(a single sThread,equential flow of control)/執(zhí)行路徑,一個(gè)進(jìn)程至少要有一個(gè)以上的線程
1) 線程又被稱為輕量級(jí)進(jìn)程(light weight process)
2) Threads run at then same time,independently of one another
3) 一個(gè)進(jìn)程可擁有多個(gè)并行行的(concurrent)線程
4) 一個(gè)進(jìn)程中的線程共享相同的內(nèi)存單元/內(nèi)存地址空間->可以訪問(wèn)相同的變量和對(duì)象,而且它們從同一堆中分配對(duì)象->通信、數(shù)據(jù)數(shù)據(jù)交換、同步操作
5) 由線線程間的通信是在同一地址同空上進(jìn)行的,所以不需要額外的通信機(jī)制,這就使得通信更簡(jiǎn)便,而且信息傳遞的速度也更快
6) 進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位
7) 進(jìn)程在執(zhí)行過(guò)程中擁有獨(dú)立的內(nèi)存單元,而多個(gè)線程共享內(nèi)存,從而極大地提高了程序的的運(yùn)行效率
8) 一個(gè)程序至少有有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程
9) 線程是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位
10) 線程自己基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一級(jí)寄存器和棧),但是它可與與同屬一個(gè)進(jìn)程的的其他線程共享進(jìn)程所擁有的全部資源
11) 線程的劃分尺度小于進(jìn)程(資源比進(jìn)程少),使得多線程程序的并發(fā)性高
12) 線程不能獨(dú)立執(zhí)行,必須依存在進(jìn)程中
13) 線程和進(jìn)程在使用上各有優(yōu)缺點(diǎn):線程執(zhí)行開銷小,但不利于資源的管理和保護(hù),而進(jìn)程正相反
區(qū)別 | 進(jìn)程 | 線程 |
根本區(qū)域 | 作為資源分配的單位 | 調(diào)度和執(zhí)行的單位 |
開銷 | 每個(gè)進(jìn)程都有獨(dú)立的代碼和和數(shù)據(jù)空間(進(jìn)程上下文),進(jìn)程進(jìn)程間的切換會(huì)有較大的的開銷 | 線程可以看成是輕量級(jí)的進(jìn)程,同一類線程共享代碼和數(shù)據(jù)空間,每個(gè)線程有獨(dú)立的運(yùn)行棧和程序計(jì)數(shù)器PC,線程切換的開銷小 |
所處環(huán)境 | 在操作系統(tǒng)中能同時(shí)運(yùn)行多多個(gè)任務(wù)(程序) | 在同一應(yīng)用程序中有多個(gè)順序流同時(shí)執(zhí)行 |
分配內(nèi)存 | 系統(tǒng)在運(yùn)行的時(shí)候會(huì)為每個(gè)進(jìn)程分配不同的內(nèi)存區(qū)域 | 除了CPU之外,不會(huì)為線程分配內(nèi)存(線程所使用的資源是它所屬的進(jìn)程資源),線程組只能共享資源 |
包含關(guān)系 | 沒(méi)有線程的進(jìn)程是可以被看作單線程的,如果一個(gè)進(jìn)程內(nèi)擁有多個(gè)線程,則執(zhí)行過(guò)程不是一條線的,而是多條線(線程)共同完成的 | 線程是進(jìn)程的一部分,所以線程有的時(shí)候被稱為是輕權(quán)進(jìn)程或者輕量級(jí)進(jìn)程進(jìn)程 |
python的thread模塊是比較底層的模塊
python的threading模塊是對(duì)thread做了一些包裝的,可以更加方便的被使用 
threading模塊

例,統(tǒng)計(jì)線程數(shù)

例,線程的子類化

線程的幾種狀態(tài)
多線程程序的執(zhí)行順序是不確定的。當(dāng)執(zhí)行到sleep語(yǔ)句時(shí),線程將被阻塞(BLOCKED),到sleep線束后,線程進(jìn)入就緒(RUNNABLE)狀態(tài),等待調(diào)度。
而線程調(diào)度將自行選擇一個(gè)線程執(zhí)行。代碼中只能保證每個(gè)線程都運(yùn)行完整個(gè)run函數(shù),但是線程啟動(dòng)順序、run函數(shù)中每次循環(huán)的執(zhí)行順序都不能確定。

線程共享全局變量
在一個(gè)進(jìn)程內(nèi)的所有線程共享全局變量,能夠在不適用其他方式的前提下完成多線程之間的數(shù)據(jù)共享(這點(diǎn)要比多進(jìn)程要好)
缺點(diǎn)就是,線程是對(duì)全局變量隨意遂改可能造成多線程之間對(duì)全局變量的混亂(即線程非安全)
方法不帶參數(shù):

方法帶參數(shù),不可變類型(未對(duì)全局變量進(jìn)行修改)

方法帶參數(shù),可變類型(可以對(duì)全局變量進(jìn)行修改)

線程同步問(wèn)題

g_num+1 -> g_num=g_num+1
g_num原先存放在內(nèi)存,g_num+=1操作分三步:
1、CPU得先從內(nèi)存將g_num的值讀到寄存器;
2、在寄存器中將讀出來(lái)的數(shù)加1;
3、將寄存器的值寫回到內(nèi)存
不同線程不同步,導(dǎo)致寄存器寫入值時(shí),出現(xiàn)紊亂。
1. 線程同步說(shuō)明
1) 當(dāng)多個(gè)線程幾乎同時(shí)修改某一個(gè)共享數(shù)據(jù)的時(shí)候,需要進(jìn)行同步控制
2) 線程同步能夠保證多個(gè)線程安全訪問(wèn)競(jìng)爭(zhēng)資源,最簡(jiǎn)單的同步機(jī)制是引入互斥鎖
3) 互斥鎖保證了每次只有一個(gè)線程進(jìn)行寫入操作,從而保證了多線程情況下數(shù)據(jù)的正確性
4) 某個(gè)線程要更改共享數(shù)據(jù)時(shí),先將其鎖定,此時(shí)資源的狀態(tài)為“鎖定”,其他線程不能更改;直到該線程釋放資源,將資源的狀態(tài)變成“非鎖定”,其他的線程才能再次鎖定該資源
5) threading模塊中定義Lock類,可以方便的處理鎖定
創(chuàng)建鎖
mutex=Threading.Lock()
鎖定
mutex.acquire([blocking])
a) 如果設(shè)定blocking為True,則當(dāng)前線程會(huì)堵塞,直到獲取到這個(gè)鎖為止(如果沒(méi)有指定,那么默認(rèn)為True)
b) 如果設(shè)定blocking為False,則當(dāng)前線程不會(huì)堵塞
釋放
mutex.release()

2. 死鎖
在線程間共享多個(gè)資源的時(shí)候,如果兩個(gè)線程分別占有一部分資源并且同時(shí)等待對(duì)方的資源,就會(huì)造成死鎖
入到死鎖狀態(tài),可以使用ctrl+Z退出
3. 通過(guò)鎖控制線程的執(zhí)行順序

4. python的Queue模塊中提供了同步的、線程安全的隊(duì)列類,包括
FIFO(先入先出)隊(duì)列Queue
LIFO(后入先出)隊(duì)列LifoQueue #棧
優(yōu)先級(jí)列隊(duì)PriorityQueue
這些隊(duì)列都實(shí)現(xiàn)了鎖原語(yǔ)(可以理解為原子操作,即要么不做,要么就做完),能夠在多線程中直接使用

5. ThreadLocal變量
一個(gè)ThreadLocal變量雖然是全局變量,但每個(gè)線程都只能讀寫自己線程的獨(dú)立副本,互不干擾。ThreadLocal解決了參數(shù)在一個(gè)線程中各個(gè)函數(shù)之間互相傳遞的問(wèn)題
可以理解為全局變量local_school是一個(gè)dict,可以綁定其他變量
ThreadLocal最常用的地方就是為每個(gè)線程綁定一個(gè)數(shù)據(jù)庫(kù)連接,http請(qǐng)求,用戶身份信息等,這樣一個(gè)線程的所有調(diào)用到的處理函數(shù)都可以非常方便地訪問(wèn)這些資源。ThreadLocal 真正做到了線程之間的數(shù)據(jù)隔離
