日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python锁机制_python基础(锁机制,守护线程,线程队列,线程池)

發布時間:2024/7/23 python 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python锁机制_python基础(锁机制,守护线程,线程队列,线程池) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、?互斥鎖(Lock)與遞歸鎖(RLock)機制

1.1?由互斥鎖(Lock)產生的死鎖現象:

#互斥鎖(死鎖現象):

#死鎖現象:

from threading importLock

lock=Lock()

lock.acquire()print(123)

lock.acquire()#等待獲取鎖(死鎖狀態)

print(456)

lock.release()#等待釋放鎖

lock.release()print('程序結束!!!')#科學家吃面產生的死鎖現象:

from threading importLock, Threadimporttime

noodle_lock= Lock() #面條鎖

fork_lock = Lock() #叉子鎖

defeat1(name):

noodle_lock.acquire()

time.sleep(0.5)print('%s拿到面了' %name)

fork_lock.acquire()print('%s拿到叉子了' %name)print('%s吃面' %name)

fork_lock.release()print('%s放下叉子了' %name)

noodle_lock.release()print('%s放下面了' %name)defeat2(name):

fork_lock.acquire()print('%s拿到叉子了' %name)

noodle_lock.acquire()print('%s拿到面了' %name)print('%s吃面' %name)

noodle_lock.release()print('%s放下面了' %name)

fork_lock.release()print('%s放下叉子了' %name)#三個線程(科學家)需同時獲取叉子和面條才能吃到面條

Thread(target=eat1, args=('Annie',)).start()

Thread(target=eat2, args=('Lisa',)).start()

Thread(target=eat1, args=('Jane',)).start()

View Code

1.2?解決由互斥鎖產生的死鎖,可重入鎖(遞歸鎖:RLock)解決方法:

#遞歸鎖(可重入鎖):

#方式一:#RLock:解決死鎖問題(建議少用遞歸鎖,一般程序的遞歸鎖的出現都是程序設計不合理導致):

from threading importRLock, Threadimporttime

fork_lock= noodle_lock =RLock()defeat1(name):

noodle_lock.acquire()#獲取遞歸鎖(進入第一層)

print('%s拿到面了' %name)

time.sleep(0.5)

fork_lock.acquire()#獲取遞歸鎖(進入第二層)

print('%s拿到叉子了' %name)print('%s吃面' %name)

fork_lock.release()#釋放遞歸鎖(出第二層)

print('%s放下叉子了' %name)

noodle_lock.release()#釋放遞歸鎖(出第一層)

print('%s放下面了' %name)defeat2(name):

fork_lock.acquire()print('%s拿到叉子了' %name)

noodle_lock.acquire()print('%s拿到面了' %name)print('%s吃面' %name)

noodle_lock.release()print('%s放下面了' %name)

fork_lock.release()print('%s放下叉子了' %name)

Thread(target=eat1, args=('Annie',)).start() #線程一

Thread(target=eat2, args=('Lisa',)).start() #線程二

Thread(target=eat1, args=('Jane',)).start() #線程三

#方式二:#直接使用互斥鎖結果科學家吃面問題:

from threading importLock, Thread

lock=Lock()defeat1(name):

lock.acquire()#獲取鎖

print('%s拿到面了' %name)print('%s拿到叉子了' %name)print('%s吃面' %name)print('%s放下叉子了' %name)print('%s放下面了' %name)

lock.release()#釋放鎖

defeat2(name):

lock.acquire()print('%s拿到叉子了' %name)print('%s拿到面了' %name)print('%s吃面' %name)print('%s放下面了' %name)print('%s放下叉子了' %name)

lock.release()

Thread(target=eat1, args=('Annie',)).start() #線程一

Thread(target=eat2, args=('Lisa',)).start() #線程二

Thread(target=eat1, args=('Jane',)).start() #線程三

View Code

1.3?總結:

gil鎖機制:保證線程同一時刻只能一個線程訪問CPU,不可能有兩個線程同時在CPU上執行指令

lock鎖機制:保證某一段代碼 在沒有執行完畢之后,不可能有另一個線程也執行這一段代碼

二、?線程鎖實現

為什么要使用線程鎖:

1.?同一時刻同一段代碼,只能有一個進程來執行這段代碼

2. 鎖的應用場景,當多個進程需要操作同一個文件/數據庫的時候 ,

3. 會產生數據不安全,我們應該使用鎖來避免多個進程同時修改一個文件

示例:

#示例:

importjsonimporttimefrom multiprocessing importProcess, Lock#查詢余票

defsearch_ticket(name):

with open('ticket', encoding='utf-8') as f:

dic=json.load(f)print('%s查詢余票為%s' % (name, dic['count']))#購買車票

defbuy_ticket(name):

with open('ticket', encoding='utf-8') as f:

dic=json.load(f)

time.sleep(2)if dic['count'] >= 1:print('%s買到票了' %name)

dic['count'] -= 1time.sleep(2)

with open('ticket', mode='w', encoding='utf-8') as f:

json.dump(dic, f)else:print('余票為0,%s沒買到票' %name)#使用線程鎖方式一:

defuse1(name, lock):

search_ticket(name)print('%s在等待' %name)

lock.acquire()#獲取鎖

print('%s開始執行了' %name)

buy_ticket(name)

lock.release()#釋放鎖

#使用線程鎖方式二:

defuse2(name, lock):"""# with lock:

# 代碼塊

# 上下文管理:在__enter__方法中獲取鎖(acquire),在__exit__方法中釋放鎖(release)"""search_ticket(name)print('%s在等待' %name)

with lock:#獲取鎖 + 釋放鎖

print('%s開始執行了' %name)

buy_ticket(name)if __name__ == '__main__':

lock=Lock()

l= ['alex', 'wusir', 'baoyuan', 'taibai']for name inl:

Process(target=use1, args=(name, lock)).start() #方式一

Process(target=use2, args=(name, lock)).start() #方式二

View Code

三、?隊列(Queue,LifoQueue,PriorityQueue)的使用

3.1?先進先出隊列(Queue):

#先進先出隊列#Queue就是一個線程隊列的類,自帶lock鎖,實現了線程安全的數據類型

from queue importQueue

q=Queue()

q.put({1, 2, 3})

q.put_nowait('abc')print(q.get_nowait()) #獲取一個值,如果沒有拋出異常

print(q.get())

q.empty()#判斷是否為空

q.full() #判斷是否為滿

q.qsize() #查看隊列的大小

View Code

3.2?先進后出隊列(棧:LifoQueue):

#先進后出的隊列(last in first out):#線程安全的隊列 棧和后進先出的場景都可以用

from queue importLifoQueue

lfq=LifoQueue()

lfq.put(1)

lfq.put('abc')

lfq.put({'1', '2'})print(lfq.get()) #{'2', '1'}

print(lfq.get()) #abc

print(lfq.get()) #1

View Code

3.3?優先級隊列(PriorityQueue):

#優先級隊列:

from queue importPriorityQueue

pq=PriorityQueue()

pq.put((10, 'aaa'))

pq.put((2, 'bbb'))

pq.put((20, 'ccc'))print(pq.get()) #最想獲取到優先級最高的2,以元組形式返回 (2, 'bbb')

print(pq.get()) #(10, 'aaa')

print(pq.get()) #(20, 'ccc')

View Code

四、線程隊列(生產者與消費者模型)

#生產者與消費者示例:

importtimeimportrandomfrom queue importQueuefrom threading importThread#生產者

defproducer(q):for i in range(10):

time.sleep(random.random())

food= 'Spam %s' %iprint('%s生產了%s' % ('Jane', food))

q.put(food)#消費者

defconsumer(q, name):whileTrue:

food= q.get() #food = 食物/None

if not food: break #當消費者消費完成后,最后拿到None時,退出消費者程序

time.sleep(random.uniform(1, 2))print('%s 吃了 %s' %(name, food))if __name__ == '__main__':

q=Queue()

p1= Thread(target=producer, args=(q,)) #生產者

p1.start()

c1= Thread(target=consumer, args=(q, 'Lisa')) #消費者

c1.start()

c2= Thread(target=consumer, args=(q, 'Annie')) #消費者

c2.start()

p1.join()

q.put(None)#生產者完成生產后,隊列最后加入None,表示已經生產完成

q.put(None) #每個消費者需要None退出程序

View Code

五、守護線程:

5.1 守護線程的定義:

1. 主線程會等待子線程的結束而結束

2. 守護線程會守護主線程和所有的子線程

3. 守護線程會隨著主線程的結束而結束,主線程結束,進程資源回收,守護線程被銷毀

示例:

#守護線程示例:

importtimefrom threading importThread#守護線程

defdaemon_func():whileTrue:

time.sleep(0.5)print('守護線程')#其他子線程

defson_func():print('start son')

time.sleep(5)print('end son')

t= Thread(target=daemon_func) #開啟守護線程

t.daemon =True

t.start()

Thread(target=son_func).start() #開啟son_func子線程

time.sleep(3)print('主線程結束') #主線程代碼結束后,等待子線程son_func結束

View Code

總結:

守護進程 :只會守護到主進程的代碼結束

守護線程 :會守護所有其他非守護線程的結束

六、線程池

線程池模塊與進程池共用同一個模塊:concureent.futures

示例:

#線程池:

from urllib.request importurlopenfrom concurrent.futures import ThreadPoolExecutor #導入線程池類

#獲取網頁

defget_html(name, addr):

ret=urlopen(addr)return {'name': name, 'content': ret.read()}#保存數據

defcache_page(ret_obj):

dic=ret_obj.result()

with open(dic['name'] + '.html', 'wb') as f:

f.write(dic['content'])

url_dic={'協程': 'http://www.cnblogs.com/Eva-J/articles/8324673.html','線程': 'http://www.cnblogs.com/Eva-J/articles/8306047.html','目錄': 'https://www.cnblogs.com/Eva-J/p/7277026.html','百度': 'http://www.baidu.com','sogou': 'http://www.sogou.com'}#創建20個線程#方式一:

t = ThreadPoolExecutor(20) #實例化線程池對象

for url inurl_dic:

task= t.submit(get_html, url, url_dic[url]) #提交線程任務

task.add_done_callback(cache_page) #函數回調,數據保存

#方式二:

with ThreadPoolExecutor(20) as t: #上下文管理方式實現實例化的線程池

for url inurl_dic:

task=t.submit(get_html, url, url_dic[url])

task.add_done_callback(cache_page)

View Code

總結

以上是生活随笔為你收集整理的python锁机制_python基础(锁机制,守护线程,线程队列,线程池)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。