進程和線程
進程(Process)是計算機中的程序關(guān)于數(shù)據(jù)集合上的一次活動,是系統(tǒng)進行資源分配和調(diào)度的基本單位。簡單的說,進程是正在運行的程序的實例。
一般來說,進程一般由文本區(qū)域、數(shù)據(jù)區(qū)域和堆棧組成。文本區(qū)域存儲處理器執(zhí)行的代碼,數(shù)據(jù)區(qū)域存儲變量和進程執(zhí)行期間使用的動態(tài)分配的內(nèi)存,堆棧則存儲活動過程中調(diào)用的指令和本地變量。
線程(Thread)是程序執(zhí)行流的最小單元,線程只擁有運行所必須的資源,其他的資源和該進程中的其他線程共享。有時也被稱之為輕量級進程(LightWeight Process,LWP)。一般一個進程中都有一個主線程。
各自優(yōu)缺點:
進程擁有獨立的地址空間和資源,進程間通信IPC比較麻煩,當(dāng)一個進程崩潰后,不會對其他進程造成影響,故多進程程序比較健壯。但進程間切換耗費的資源比較大,時間較長。
線程由于共享所屬進程的資源,故線程間通信比較簡單。線程所擁有的資源比較少,線程間的切換耗時短。
PIL
說起python和線程,那就不得不說一下PIL了,PIL是全局解釋器鎖(Global Interpreter Lock),該鎖保證同時只能有一個線程運行。
在多線程中,python虛擬機的運行方式如下:
1. 設(shè)置GIL
2. 切換進一個線程運行
3. 執(zhí)行一下一個操作:
- 指定數(shù)量的字節(jié)碼指令
- 線程主動讓出控制權(quán)
4. 切換線程
5. 解鎖GIL
對于python來說,GIL會在線程進行I/O調(diào)用前被釋放,以便其他的線程運行,這也就是Python更適合做I/O密集型的工作。
python中提供了多個模塊來支持多線程編程,如thread,threading,Queue模塊,其中thread模塊提供了基本的線程和鎖定支持,threading提供了更高級別、功能更全面的線程管理,Queue模塊可以創(chuàng)建隊列數(shù)據(jù)結(jié)構(gòu),在多個線程之間進行數(shù)據(jù)共享。
thread模塊
| 函數(shù)方法 | 描述 |
|---|---|
| thread模塊函數(shù) | |
| start_new_thread(function,args,kwargs=None) | 派生一個新的線程 |
| allocate_lock() | 分配LockType鎖對象 |
| exit() | 退出線程 |
| LockType鎖對象方法 | |
| acquire(wait=None) | 獲取鎖對象 |
| locked() | 是否獲取鎖對象 |
| release() | 釋放鎖對象 |
一般來說thread不常用,原因如下:
- thread模塊中所擁有的同步元語只有一個,即LockType,
- thread對于進程的進入退出沒有控制,當(dāng)主線程結(jié)束時,所有的其他線程也會強制結(jié)束,不會發(fā)出警告或清理。
- 不支持守護線程
- thread所支持的操作很少
在python3中thread模塊被更名為_thread
下面給出一個python3關(guān)于_thread的簡單例子:
import _thread
import random
from time import ctime, sleep
def loop(nloop, nsec, lock):
print('start loop:', nloop, 'nsec:', nsec, 'at:', ctime())
sleep(nsec)
print('end loop', nloop, 'done at:', ctime())
lock.release()
def main():
print('starting at:', ctime())
locks = []
for i in range(2):
lock = _thread.allocate_lock()
lock.acquire()
locks.append(lock)
for i in range(2):
_thread.start_new_thread(loop, (i, random.randint(1, 4), locks[i]))
for i in range(2):
while locks[i].locked():
pass
print('all down at:', ctime())
if __name__ == '__main__':
main()
在這個例子中,首先通過_thread_allocate_lock()來生成鎖對象,并通過acquire()來獲取鎖,這樣就相當(dāng)于將鎖鎖上,然后將該鎖傳遞給每個線程中。
線程中操作很簡單,休眠傳遞過來的時間,然后釋放鎖。
在主線程中,不停的去判斷兩個鎖是否鎖住,避免主線程執(zhí)行完導(dǎo)致兩個線程直接被強制結(jié)束。運行的結(jié)果如下:
starting at: Thu Sep 7 09:57:36 2017
start loop: 0 nsec: 2 at: Thu Sep 7 09:57:36 2017
start loop: 1 nsec: 4 at: Thu Sep 7 09:57:36 2017
end loop 0 done at: Thu Sep 7 09:57:38 2017
end loop 1 done at: Thu Sep 7 09:57:40 2017
all down at: Thu Sep 7 09:57:40 2017
python多線程就暫時講到這里了。