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