1. 多線程
線程:是進程中一個“單一的連續(xù)控制流程”(a single sThread,equential flow of control)/執(zhí)行路徑,一個進程至少要有一個以上的線程
1) 線程又被稱為輕量級進程(light weight process)
2) Threads run at then same time,independently of one another
3) 一個進程可擁有多個并行行的(concurrent)線程
4) 一個進程中的線程共享相同的內(nèi)存單元/內(nèi)存地址空間->可以訪問相同的變量和對象,而且它們從同一堆中分配對象->通信、數(shù)據(jù)數(shù)據(jù)交換、同步操作
5) 由線線程間的通信是在同一地址同空上進行的,所以不需要額外的通信機制,這就使得通信更簡便,而且信息傳遞的速度也更快
6) 進程是系統(tǒng)進行資源分配和調(diào)度的一個獨立單位
7) 進程在執(zhí)行過程中擁有獨立的內(nèi)存單元,而多個線程共享內(nèi)存,從而極大地提高了程序的的運行效率
8) 一個程序至少有有一個進程,一個進程至少有一個線程
9) 線程是進程的一個實體,是CPU調(diào)度和分派的基本單位,它是比進程更小的能獨立運行的基本單位
10) 線程自己基本上不擁有系統(tǒng)資源,只擁有一點在運行中必不可少的資源(如程序計數(shù)器,一級寄存器和棧),但是它可與與同屬一個進程的的其他線程共享進程所擁有的全部資源
11) 線程的劃分尺度小于進程(資源比進程少),使得多線程程序的并發(fā)性高
12) 線程不能獨立執(zhí)行,必須依存在進程中
13) 線程和進程在使用上各有優(yōu)缺點:線程執(zhí)行開銷小,但不利于資源的管理和保護,而進程正相反
區(qū)別 | 進程 | 線程 |
根本區(qū)域 | 作為資源分配的單位 | 調(diào)度和執(zhí)行的單位 |
開銷 | 每個進程都有獨立的代碼和和數(shù)據(jù)空間(進程上下文),進程進程間的切換會有較大的的開銷 | 線程可以看成是輕量級的進程,同一類線程共享代碼和數(shù)據(jù)空間,每個線程有獨立的運行棧和程序計數(shù)器PC,線程切換的開銷小 |
所處環(huán)境 | 在操作系統(tǒng)中能同時運行多多個任務(wù)(程序) | 在同一應(yīng)用程序中有多個順序流同時執(zhí)行 |
分配內(nèi)存 | 系統(tǒng)在運行的時候會為每個進程分配不同的內(nèi)存區(qū)域 | 除了CPU之外,不會為線程分配內(nèi)存(線程所使用的資源是它所屬的進程資源),線程組只能共享資源 |
包含關(guān)系 | 沒有線程的進程是可以被看作單線程的,如果一個進程內(nèi)擁有多個線程,則執(zhí)行過程不是一條線的,而是多條線(線程)共同完成的 | 線程是進程的一部分,所以線程有的時候被稱為是輕權(quán)進程或者輕量級進程進程 |
python的thread模塊是比較底層的模塊
python的threading模塊是對thread做了一些包裝的,可以更加方便的被使用
threading模塊
例,統(tǒng)計線程數(shù)
例,線程的子類化
線程的幾種狀態(tài)
多線程程序的執(zhí)行順序是不確定的。當執(zhí)行到sleep語句時,線程將被阻塞(BLOCKED),到sleep線束后,線程進入就緒(RUNNABLE)狀態(tài),等待調(diào)度。
而線程調(diào)度將自行選擇一個線程執(zhí)行。代碼中只能保證每個線程都運行完整個run函數(shù),但是線程啟動順序、run函數(shù)中每次循環(huán)的執(zhí)行順序都不能確定。
線程共享全局變量
在一個進程內(nèi)的所有線程共享全局變量,能夠在不適用其他方式的前提下完成多線程之間的數(shù)據(jù)共享(這點要比多進程要好)
缺點就是,線程是對全局變量隨意遂改可能造成多線程之間對全局變量的混亂(即線程非安全)
方法不帶參數(shù):
方法帶參數(shù),不可變類型(未對全局變量進行修改)
方法帶參數(shù),可變類型(可以對全局變量進行修改)
線程同步問題
g_num+1 -> g_num=g_num+1
g_num原先存放在內(nèi)存,g_num+=1操作分三步:
1、CPU得先從內(nèi)存將g_num的值讀到寄存器;
2、在寄存器中將讀出來的數(shù)加1;
3、將寄存器的值寫回到內(nèi)存
不同線程不同步,導致寄存器寫入值時,出現(xiàn)紊亂。
1. 線程同步說明
1) 當多個線程幾乎同時修改某一個共享數(shù)據(jù)的時候,需要進行同步控制
2) 線程同步能夠保證多個線程安全訪問競爭資源,最簡單的同步機制是引入互斥鎖
3) 互斥鎖保證了每次只有一個線程進行寫入操作,從而保證了多線程情況下數(shù)據(jù)的正確性
4) 某個線程要更改共享數(shù)據(jù)時,先將其鎖定,此時資源的狀態(tài)為“鎖定”,其他線程不能更改;直到該線程釋放資源,將資源的狀態(tài)變成“非鎖定”,其他的線程才能再次鎖定該資源
5) threading模塊中定義Lock類,可以方便的處理鎖定
創(chuàng)建鎖
mutex=Threading.Lock()
鎖定
mutex.acquire([blocking])
a) 如果設(shè)定blocking為True,則當前線程會堵塞,直到獲取到這個鎖為止(如果沒有指定,那么默認為True)
b) 如果設(shè)定blocking為False,則當前線程不會堵塞
釋放
mutex.release()
2. 死鎖
在線程間共享多個資源的時候,如果兩個線程分別占有一部分資源并且同時等待對方的資源,就會造成死鎖
入到死鎖狀態(tài),可以使用ctrl+Z退出
3. 通過鎖控制線程的執(zhí)行順序
4. python的Queue模塊中提供了同步的、線程安全的隊列類,包括
FIFO(先入先出)隊列Queue
LIFO(后入先出)隊列LifoQueue #棧
優(yōu)先級列隊PriorityQueue
這些隊列都實現(xiàn)了鎖原語(可以理解為原子操作,即要么不做,要么就做完),能夠在多線程中直接使用
5. ThreadLocal變量
一個ThreadLocal變量雖然是全局變量,但每個線程都只能讀寫自己線程的獨立副本,互不干擾。ThreadLocal解決了參數(shù)在一個線程中各個函數(shù)之間互相傳遞的問題
可以理解為全局變量local_school是一個dict,可以綁定其他變量
ThreadLocal最常用的地方就是為每個線程綁定一個數(shù)據(jù)庫連接,http請求,用戶身份信息等,這樣一個線程的所有調(diào)用到的處理函數(shù)都可以非常方便地訪問這些資源。ThreadLocal 真正做到了線程之間的數(shù)據(jù)隔離