1.進程
1.1進程的創(chuàng)建-fork
1.1.1進程 與 程序
- 編寫完畢的代碼,在沒有運行的時候,稱之為程序
- 正在運行著的代碼缅阳,就成為進程
1.1.2 fork()
import os
# 注意差牛,fork函數(shù),只在Unix/Linux/Mac上運行钾唬,windows不可以
pid = os.fork()
if pid == 0:
print('哈哈1')
else:
print('哈哈2')
說明:
- 程序執(zhí)行到os.fork()時万哪,操作系統(tǒng)會創(chuàng)建一個新的進程(子進程),然后復(fù)制父進程的所有信息到子進程中
- 然后父進程和子進程都會從fork()函數(shù)中得到一個返回值抡秆,在子進程中這個值一定是0奕巍,而父進程中是子進程的 id號
1.1.3 getpid()、getppid()
import os
rpid = os.fork()
if rpid<0:
print("fork調(diào)用失敗儒士。")
elif rpid == 0:
print("我是子進程(%s)的止,我的父進程是(%s)"%(os.getpid(),os.getppid()))
x+=1
else:
print("我是父進程(%s)着撩,我的子進程是(%s)"%(os.getpid(),rpid))
print("父子進程都可以執(zhí)行這里的代碼")
運行結(jié)果:
我是父進程(19360)诅福,我的子進程是(19361)
父子進程都可以執(zhí)行這里的代碼
我是子進程(19361),我的父進程是(19360)
父子進程都可以執(zhí)行這里的代碼
1.1.4 多進程修改全局變量
#coding=utf-8
import os
import time
num = 0
# 注意拖叙,fork函數(shù)氓润,只在Unix/Linux/Mac上運行,windows不可以
pid = os.fork()
if pid == 0:
num+=1
print('哈哈1---num=%d'%num)
else:
time.sleep(1)
num+=1
print('哈哈2---num=%d'%num)
總結(jié)
多進程中薯鳍,每個進程中所有數(shù)據(jù)(包括全局變量)都各有擁有一份咖气,互不影響
Process語法結(jié)構(gòu)如下:
Process([group [, target [, name [, args [, kwargs]]]]])
- target:表示這個進程實例所調(diào)用對象;
- args:表示調(diào)用對象的位置參數(shù)元組;
- kwargs:表示調(diào)用對象的關(guān)鍵字參數(shù)字典崩溪;
- name:為當(dāng)前進程實例的別名浅役;
- group:大多數(shù)情況下用不到;
Process類常用方法:
- is_alive():判斷進程實例是否還在執(zhí)行悯舟;
- join([timeout]):是否等待進程實例執(zhí)行結(jié)束担租,或等待多少秒;
- start():啟動進程實例(創(chuàng)建子進程)抵怎;
- run():如果沒有給定target參數(shù)奋救,對這個對象調(diào)用start()方法時,就將執(zhí)行對象中的run()方法反惕;
- terminate():不管任務(wù)是否完成尝艘,立即終止;
Process類常用屬性:
- name:當(dāng)前進程實例別名姿染,默認為Process-N背亥,N為從1開始遞增的整數(shù);
- pid:當(dāng)前進程實例的PID值悬赏;
1.1.5 進程池Pool
初始化Pool時狡汉,可以指定一個最大進程數(shù),當(dāng)有新的請求提交到Pool中時闽颇,如果池還沒有滿盾戴,那么就會創(chuàng)建一個新的進程用來執(zhí)行該請求;但如果池中的進程數(shù)已經(jīng)達到指定的最大值兵多,那么該請求就會等待尖啡,直到池中有進程結(jié)束,才會創(chuàng)建新的進程來執(zhí)行剩膘,請看下面的實例:
multiprocessing.Pool常用函數(shù)解析:
- apply_async(func[, args[, kwds]]) :使用非阻塞方式調(diào)用func(并行執(zhí)行衅斩,堵塞方式必須等待上一個進程退出才能執(zhí)行下一個進程),args為傳遞給func的參數(shù)列表怠褐,kwds為傳遞給 func的關(guān)鍵字參數(shù)列表畏梆;
- apply(func[, args[, kwds]]):使用阻塞方式調(diào)用func
- close():關(guān)閉Pool,使其不再接受新的任務(wù)奈懒;
- terminate():不管任務(wù)是否完成奠涌,立即終止;
- join():主進程阻塞筐赔,等待子進程的退出铣猩, 必須在close或terminate之后使用;
1.1.6進程間通信-Queue
初始化Queue()對象時(例如:q=Queue())茴丰,若括號中沒有指定最大可接收的消息數(shù)量达皿,或數(shù)量為負值天吓,那么就代表可接受的消息數(shù)量沒有上限(直到內(nèi)存的盡頭);
- Queue.qsize():返回當(dāng)前隊列包含的消息數(shù)量峦椰;
- Queue.empty():如果隊列為空龄寞,返回True,反之False 汤功;
- Queue.full():如果隊列滿了物邑,返回True,反之False;
- Queue.get([block[, timeout]]):獲取隊列中的一條消息滔金,然后將其從列隊中移除色解,block默認值為True;
1)如果block使用默認值餐茵,且沒有設(shè)置timeout(單位秒)科阎,消息列隊如果為空,此時程序?qū)⒈蛔枞ㄍT谧x取狀態(tài))忿族,直到從消息列隊讀到消息為止锣笨,如果設(shè)置了timeout,則會等待timeout秒道批,若還沒讀取到任何消息错英,則拋出"Queue.Empty"異常;
2)如果block值為False隆豹,消息列隊如果為空椭岩,則會立刻拋出"Queue.Empty"異常;
Queue.get_nowait():相當(dāng)Queue.get(False)噪伊;
Queue.put(item,[block[, timeout]]):將item消息寫入隊列簿煌,block默認值為True氮唯;
1)如果block使用默認值鉴吹,且沒有設(shè)置timeout(單位秒),消息列隊如果已經(jīng)沒有空間可寫入惩琉,此時程序?qū)⒈蛔枞ㄍT趯懭霠顟B(tài))豆励,直到從消息列隊騰出空間為止,如果設(shè)置了timeout瞒渠,則會等待timeout秒良蒸,若還沒空間,則拋出"Queue.Full"異常伍玖;
2)如果block值為False嫩痰,消息列隊如果沒有空間可寫入,則會立刻拋出"Queue.Full"異常窍箍;
2. 線程
多線程執(zhí)行
import threading
import time
def saySorry():
print("親愛的串纺,我錯了丽旅,我能吃飯了嗎?")
time.sleep(1)
if __name__ == "__main__":
for i in range(5):
t = threading.Thread(target=saySorry)
t.start() #啟動線程纺棺,即讓線程開始執(zhí)行
2.1 線程的執(zhí)行順序
總結(jié)
1.每個線程一定會有一個名字榄笙,盡管上面的例子中沒有指定線程對象的name,但是python會自動為線程指定一個名字祷蝌。
2.當(dāng)線程的run()方法結(jié)束時該線程完成茅撞。
3.無法控制線程調(diào)度程序,但可以通過別的方式來影響線程調(diào)度的方式巨朦。
4.線程的幾種狀態(tài)
2.2 多線程-共享全局變量
總結(jié):
- 在一個進程內(nèi)的所有線程共享全局變量米丘,能夠在不適用其他方式的前提下完成多線程之間的數(shù)據(jù)共享(這點要比多進程要好)
- 缺點就是,線程是對全局變量隨意遂改可能造成多線程之間對全局變量的混亂(即線程非安全)
2.2 進程VS線程
- 進程糊啡,能夠完成多任務(wù)蠕蚜,比如 在一臺電腦上能夠同時運行多個QQ
- 線程,能夠完成多任務(wù)悔橄,比如 一個QQ中的多個聊天窗口
定義不同
進程是系統(tǒng)進行資源分配和調(diào)度的一個獨立單位.
線程是進程的一個實體,是CPU調(diào)度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程自己基本上不擁有系統(tǒng)資源,只擁有一點在運行中必不可少的資源(如程序計數(shù)器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源.
2.3 什么是同步
同步就是協(xié)同步調(diào)靶累,按預(yù)定的先后次序進行運行。
2.4 互斥鎖
當(dāng)多個線程幾乎同時修改某一個共享數(shù)據(jù)的時候癣疟,需要進行同步控制
線程同步能夠保證多個線程安全訪問競爭資源挣柬,最簡單的同步機制是引入互斥鎖。
互斥鎖為資源引入一個狀態(tài):鎖定/非鎖定睛挚。
某個線程要更改共享數(shù)據(jù)時邪蛔,先將其鎖定,此時資源的狀態(tài)為“鎖定”扎狱,其他線程不能更改侧到;直到該線程釋放資源,將資源的狀態(tài)變成“非鎖定”淤击,其他的線程才能再次鎖定該資源匠抗。互斥鎖保證了每次只有一個線程進行寫入操作污抬,從而保證了多線程情況下數(shù)據(jù)的正確性汞贸。
threading模塊中定義了Lock類,可以方便的處理鎖定:
#創(chuàng)建鎖
mutex = threading.Lock()
#鎖定
mutex.acquire([blocking])
#釋放
mutex.release()
其中印机,鎖定方法acquire可以有一個blocking參數(shù)矢腻。
- 如果設(shè)定blocking為True,則當(dāng)前線程會堵塞射赛,直到獲取到這個鎖為止(如果沒有指定多柑,那么默認為True)
- 如果設(shè)定blocking為False,則當(dāng)前線程不會堵塞
多線程-非共享數(shù)據(jù)
在多線程開發(fā)中楣责,全局變量是多個線程都共享的數(shù)據(jù)竣灌,而局部變量等是各自線程的诫隅,是非共享的
2.5 死鎖
- 死鎖
在線程間共享多個資源的時候,如果兩個線程分別占有一部分資源并且同時等待對方的資源帐偎,就會造成死鎖逐纬。
避免死鎖的方法
- 程序設(shè)計時要盡量避免(銀行家算法)
- 添加超時時間等