上海網(wǎng)絡(luò)推廣公司外包合肥seo排名扣費
進程和線程的比較
1. 進程的開銷比線程的開銷大很多
2. 進程之間的數(shù)據(jù)是隔離的,但是,線程之間的數(shù)據(jù)不隔離
3. 多個進程間的線程數(shù)據(jù)不共享----->讓進程通信(IPC)---->進程下的線程也通信了---->隊列
GIL全局解釋器鎖(重要理論)
# 雖然一個進程中開了多個線程,但在同一時刻只有一個線程在解釋器中運行,全局解釋器? ? ?鎖(GIL)來保證
# 背景信息:
? ? ?1、Python代碼運行在解釋器上嘛,有解釋器來執(zhí)行或者解釋
? ? ? 2、?Python解釋器的種類:CPython、IPython、PyPy、Jython、IronPython
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 官方下載? 交互式? ?提高速度? Java字節(jié)碼
? ? ?3. 當(dāng)前市場使用的最多(95%)的解釋器就是CPython解釋器
? ? ?4. GIL全局解釋器鎖是存在于CPython中
? ? ?5. 同一時刻只有一個線程在執(zhí)行,GIL全局解釋器鎖是為了避免多個線程搶奪資源的情況
# 在設(shè)計之初,在解釋器上添加了一把鎖? GIL
? ? ? ?哪個線程想執(zhí)行,必須拿到這把鎖,等釋放掉,別的線程才能拿
## 問題:
? ? ?1. python有GIL鎖的原因,同一個進程下多個線程,實際上同一時刻只有一個線程在執(zhí)行
? ? ?2. 只有在python上開進程用的多,其他語言一般不開多進程,只開多線程就夠了
? ? ?3. cpython解釋器開多線程不能利用多核優(yōu)勢,只有開多進程才能利用多核優(yōu)勢,其他語? ? ? ? ? ? ? ?言不存在這個問題
? ? ?4. 8核cpu電腦,充分利用起我這個8核
? ? ?5. 如果不存在GIL鎖,一個進程下,開啟8個線程,它就能夠充分利用cpu資源,跑滿cpu
? ? ?6. cpython解釋器中好多代碼,模塊都是基于GIL鎖機制寫起來的,改不了了----》開啟多? ? ? ? ? ? 進程---》每個進程下開啟的線程,可以被多個cpu調(diào)度執(zhí)行
? ? ?7. cpython解釋器:io密集型使用多線程,計算密集型使用多進程
互斥鎖
"""在多線程的情況下,同時執(zhí)行一個數(shù)據(jù),會發(fā)生數(shù)據(jù)錯亂的問題"""
n = 10 from threading import Lock import time def task(lock):lock.acquire()global ntemp = ntime.sleep(0.5)n = temp - 1lock.release() from threading import Threadif __name__ == '__main__':tt = []lock=Lock()for i in range(10):t = Thread(target=task, args=(lock, ))t.start()tt.append(t)for j in tt:j.join()print("主", n)
# 拿時間換空間,空間換時間 時間復(fù)雜度
# 面試題:既然有了GIL鎖,為什么還要互斥鎖? (多線程下)
? ???1. 第一個線程來了,拿到a=0,開始執(zhí)行a=a+1,這個時候結(jié)果a就是1了
? ? ?2. 第一個線程得到的結(jié)果1還沒有賦值回去給a,這個時候,第二個線程來了,拿到的a是? ? ? ? ? ? ?0,繼續(xù)執(zhí)行,?a=a+1結(jié)果還是1
? ? ?3. 加了互斥鎖,就能夠解決多線程下操作同一個數(shù)據(jù),發(fā)生錯亂的問題# 線程執(zhí)行過快,還未賦值,下一個線程就上來了,所以加個互斥鎖
? ? GIL鎖同時只能執(zhí)行 一 個線程
線程隊列
# 隊列可以解決數(shù)據(jù)隔離問題(進程)
? ?隊列可以保持?jǐn)?shù)據(jù)的安全(線程)
#?線程隊列:1. 先進先出? ???2. 后進先出? ? ???3. 優(yōu)先級的隊列
"""進程""" from multiprocessing import Queue """線程""" import queue queue.Queue()
# queue.Queue的缺點是它的實現(xiàn)涉及多個鎖和條件變量,因此可能會影響性能和內(nèi)存效率
"""先進先出""" import queue q=queue.Queue() # 無限大、 q.put('first') q.put('second') print(q.get()) print(q.get())
"""后進先出""" import queue # Lifo:last in first out q=queue.LifoQueue() q.put('first') q.put('second') print(q.get()) print(q.get())
"""優(yōu)先級隊列""" import queue q=queue.PriorityQueue() q.put((20,'a')) # put進入一個元組,元組的第一個元素是優(yōu)先級,數(shù)字越小優(yōu)先級越高 q.put((10,'b')) q.put((30,'c')) print(q.get()) # 數(shù)字越小優(yōu)先級越高,優(yōu)先級高的優(yōu)先出隊 print(q.get()) print(q.get())
進程池和線程池的使用(concurrent模塊)
#?池:池子、容器類型,可以盛放多個元素
#?進程池:提前定義好一個池子,然后,往這個池子里面添加進程,以后,只需要往這個進? ? ?程池里面丟任務(wù)就行了,然后,有這個進程池里面的任意一個進程來執(zhí)行任務(wù)
#?線程池:由任意一個線程來執(zhí)行任務(wù)
# 開進程池
def task(n, m):return n+m def task1():return {'username':'kevin', 'password':123}from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor def callback(res):print(res) # Future at 0x1ed5a5e5610 state=finished returned int>print(res.result()) # 3 def callback1(res):print(res) # Future at 0x1ed5a5e5610 state=finished returned int>print(res.result()) # {'username': 'kevin', 'password': 123}print(res.result().get('username'))if __name__ == '__main__':pool=ProcessPoolExecutor(3) # 定義一個進程池,里面有3個進程# pool=ThreadPoolExecutor(3) 改一下就是線程pool.submit(task, m=1, n=2).add_done_callback(callback) ## 2. 往池子里面丟任務(wù)pool.submit(task1).add_done_callback(callback1)
# 回調(diào)函數(shù),等執(zhí)行回調(diào)用這個函數(shù)
# 拿結(jié)果:print(res.result())
進程池中先主后子,如果想子進程都執(zhí)行完再執(zhí)行主進程:
pool.shutdown() # join + close print(123)
協(xié)程理論
# 進程:資源分配的基本單位
? ? 線程:?執(zhí)行的最小單位
? ? 協(xié)程:是程序員自己想出來的,不存在于操作系統(tǒng)中
? ? 并發(fā):切換+保存狀態(tài)#?協(xié)程就是單線程下的并發(fā)? ?# 遇到I/O時
#?協(xié)程是最節(jié)省資源的,進程是最消耗資源的,其次是線程
? ?監(jiān)測有沒有遇到IO,本質(zhì)上就是最大限度的利用CPU資源
? ? ? ? ? ??import gevent 模塊? ? ? 先安裝,不是內(nèi)置:pip install gevent?
猴子補丁:就可以把gevent.sleep(2) 寫成time.sleep(2)
from gevent import monkey; monkey.path_all()
gevent.joinall([g1,g2]) # 相當(dāng)于g1.join() g2.join()