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

歡迎訪問 生活随笔!

生活随笔

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

python

Python Threading 多线程编程

發布時間:2024/1/23 python 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python Threading 多线程编程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

寫在篇前

??threading模塊是python多線程處理包,使用該模塊可以很方便的實現多線程處理任務,本篇文章的基礎是需要掌握進程、線程基本概念,對PV原語、鎖等傳統同步處理方法有一定的了解。另外,threading模塊的實現是參考java多線程處理方式,并且只實現了其中的一個子集。必須說明的是,由于GIL的存在,多線程的應用主要用于IO密集型任務,不適合CPU密集型任務,如果要提高CPU的利用率,需要利用協程或則多進程編程。

Threading 方法屬性

  • threading.active_count() 返回當前活動的線程數
  • threading.current_thread() 返回當前線程的Thread對象
  • threading.get_ident() 獲取當前線程的(唯一)標識符
  • threading.enumerate() 返回一個包含當前處于活動狀態Thread 對象的list
  • threading.main_thread() 返回當前線程的主線程
  • threading.settrace(func) 為每個線程設置一個trace函數,在調用run方法之前會被執行
  • threading.setprofile(func) 同上,為每一個線程設置一個profile函數
  • threading.stack_size([size]) 設置每個線程私有棧空間大小,默認為0,若不為0不可低于32KB(32768)
  • threading.TIMEOUT_MAX 允許線程被堵塞的最長時間,按我的理解一般用不上

Thread對象

?使用Thread一共有兩種方式,同Java多線程模型:

?????(1) 繼承Thread類,并重寫且僅僅重寫__init__和 run方法,特別注意的是重寫__init__方法首先應該調用父類構造方法Thread.__init__

?????(2)將一個函數傳入到Thread類的構造函數

?Thread對象的用法以及主要方法介紹,我們用以下例子來說明一下:

#! /usr/bin/python # _*_ coding: utf-8 _*_ __author__ = 'Jeffery' __date__ = '2018/9/15 11:26'import threading import timedef func1(num):time.sleep(3)print(str(num)+':you can if you will')def func2(num):time.sleep(2)print(str(num)+':the devil is in the details')def func3(num):time.sleep(1)print(str(num)+':life is short, u need what?')def main():start = time.time()print('start mian Thread')ts = (threading.Thread(group=None, target=func1, args=(1,)),threading.Thread(group=None, target=func2, args=(2,)),threading.Thread(group=None, target=func3, args=(3,))) # 【重要】創建三個線程,分別執行func1~3for _t in ts:_t.start() # 【重要方法】啟動線程# _t.join() # 【重要方法】join方法用來告訴父線程,您要等我子線程執行完畢,你再繼續往下走,這里注釋了,所以你應該會發現程序輸出 mian Thread ends, cost 0 secsend = time.time()print('mian Thread ends, cost %d secs' % (end-start))if __name__ == '__main__':main()# 以下是執行結果 start mian Thread mian Thread ends, cost 0 secs 3:life is short, u need what? 2:the devil is in the details 1:you can if you will

Lock對象

?因為資源總是有限的,如果多個線程對同一個對象進行操作,則有可能造成資源的爭用,甚至導致死鎖。引入鎖,是一種便捷的解決方式。主要包括兩個方法,acquire()和release():

acquire(blocking=True)

??當阻塞參數設置為True(默認值)時調用,然后就會進入到locked狀態直到解鎖,返回True。

release()

??釋放占有的鎖,無返回值

#! /usr/bin/python # _*_ coding: utf-8 _*_ __author__ = 'Jeffery' __date__ = '2018/9/15 13:56'import threading import time# 臨界資源 num = 0lock = threading.Lock()def num_add(t_i):global numtime.sleep(3)if lock.acquire(): # 這句話相當于 if lock.acquire()num += 1lock.release()print('thread %d set num %d' % (t_i, num))def num_sub(t_i):global numtime.sleep(3)if lock.acquire(): # 這句話相當于 if lock.acquire()num -= 1lock.release()print('thread %d set num %d' % (t_i, num))def main():ts = []for i in range(5):t = threading.Thread(target=num_add, args=(i+1,))t.start()ts.append(t)for i in range(5):t = threading.Thread(target=num_sub, args=(5+i+1,))t.start()ts.append(t)for t in ts:t.join()print('end')if __name__ == '__main__':main() # 以下是結果 thread 4 set num 1 thread 3 set num 2 thread 5 set num 3 thread 1 set num 4 thread 2 set num 5 thread 9 set num 4 thread 10 set num 3 thread 7 set num 2 thread 6 set num 1 thread 8 set num 0 end

RLock對象

??RLock稱之為遞歸鎖,從某種角度來講屬于一種比Lock更安全的鎖,和Lock的區別在于:在同一線程內,對RLock進行多次acquire()操作(或則說RLock允許遞歸加鎖),程序不會阻塞;而如果是Lock那么將會發生堵塞。RLock所擁有的方法同上,下面例子在上例基礎上稍微改動:

#! /usr/bin/python # _*_ coding: utf-8 _*_ __author__ = 'Jeffery' __date__ = '2018/9/15 13:56'import threading import time# 臨界資源 num = 0lock = threading.RLock() # 【重點】這里必須是RLock,不能是Lockdef num_add(t_i):with lock: # 這是屬于上下文管理器的一個使用用法global numtime.sleep(3)if lock.acquire(): # 這句話相當于 if lock.acquire()num += 1lock.release()print('thread %d set num %d' % (t_i, num))def num_sub(t_i):global numtime.sleep(3)if lock.acquire(): # 這句話相當于 if lock.acquire()num -= 1lock.release()print('thread %d set num %d' % (t_i, num))def main():ts = []for i in range(5):t = threading.Thread(target=num_add, args=(i+1,))t.start()ts.append(t)for i in range(5):t = threading.Thread(target=num_sub, args=(5+i+1,))t.start()ts.append(t)for t in ts:t.join()print('end')if __name__ == '__main__':main()

Semaphore對象

?信號量是計算機科學最古老的一種同步原語,由荷蘭計算機科學家Edsger W. Dijkstra提出,通常也稱之為PV原語。在對象內部會維護一個計數器,這個計數器的初值由Semaphore初始化時給出,這個值我們一般稱之為 臨界資源數量。當臨界資源數量大于0時,線程不會被阻塞;當臨界資源等于0時再有線程請求,那將會被阻塞,直到某個線程釋放臨界資源。主要方法同RLock、Lock,下面用PV原語最(也許吧)經典的例子,哲學家問題來說明一下:

??哲學家問題:話說有五個哲學家,他們的生活方式是交替地進行思考和進餐。他們共用一張圓桌,分別坐在五張椅子上,在圓桌上有五個碗和五支筷子,平時一個哲學家進行思考,饑餓時便試圖取用其左、右最靠近他的筷子,只有在他拿到兩支筷子時才能進餐;進餐完畢,放下筷子又繼續思考。請設計一種方法,使哲學家不要餓死。

#! /usr/bin/python # _*_ coding: utf-8 _*_ __author__ = 'Jeffery' __date__ = '2018/9/15 15:35'import threading import timedef philosopher(i, chopstick_sema, sema):"""描述哲學家活動:type i: int 表示第幾個哲學家:return:no return"""while True:think(i + 1)sema.acquire(blocking=True) # 請求吃飯chopstick_sema[i].acquire() # 拿起左邊筷子chopstick_sema[((i + 1) % 5)].acquire() # 拿起右邊筷子eat(i + 1)chopstick_sema[((i + 1) % 5)].release() # 放下右邊筷子chopstick_sema[i].release() # 放下左邊筷子sema.release() # 吃飯完畢think(i + 1)def eat(phil_NO):print('philosopher %d is eating' % phil_NO)time.sleep(1)print('philosopher %d finish eating' % phil_NO)def think(phil_NO):print('philosopher %d is thinking' % phil_NO)time.sleep(2)print('philosopher %d finish thinking' % phil_NO)def main():# 為了避免死鎖,同時只允許四個哲學家吃飯sema = threading.Semaphore(value=4)chopstick_sema = [threading.Semaphore(value=1) for i in range(5)]ts = []for i in range(5):t = threading.Thread(target=philosopher, args=(i, chopstick_sema, sema))t.start()ts.append(t)for t in ts:t.join()if __name__ == '__main__':main()

Condition對象

??Condition對象總是與某種鎖相關聯,鎖對象可以通過構造函數傳入,或者它會默認創建一個鎖,并且鎖是Condition對象的一部分,不必單獨跟蹤它。

acquire()

????嘗試獲取鎖

release()

????釋放已獲得的鎖

wait(timeout=-1)

????主動進入等待阻塞狀態,直到被其他線程喚醒或則超時

wait_for(predicate, timeout=None)

????進入等待狀態,直到條件被置為True,timeout參數意思如上,predicate參數表示一個callable對象。

notify()

????喚醒其中一個線程

notify_all()

?????喚醒所有進程

舉個例子:

假設有一個緩沖區大小為5,要實現互斥存取數據,代碼如下: #! /usr/bin/python # _*_ coding: utf-8 _*_ __author__ = 'Jeffery' __date__ = '2018/9/15 16:26'import threading import timecon = threading.Condition(threading.RLock())num = 0class Producer(threading.Thread):"""生產者類"""def __init__(self):"""構造函數"""threading.Thread.__init__(self)def run(self):"""重寫 run方法:return:"""global numwith con:while True:num += 1print('生產一個產品,現在有產品%d個' % num)time.sleep(2)if num >= 5:print('緩沖區已滿')con.notify() # 喚醒等待池con.wait() # 主動進入等待池,掛起class Consumers(threading.Thread):def __init__(self):threading.Thread.__init__(self)def run(self):global numwith con:while True:num -= 1print("取出一個產品,還剩%d個" % num)time.sleep(3)if num <= 0:print('緩沖區已空')con.notify()con.wait()if __name__ == '__main__':p = Producer()c = Consumers()p.start()c.start()p.join()c.join()

Event對象

?Event,翻譯作事件,個人覺得該詞是計算機編程中的一個專有名詞。在這里用來線程之間的通信,當某一個event發生之后,其他線程做出一定的反應;或者說某一個線程等待另一個線程某個事件的發生。每一個Event對象內部維護一個flag,表征事件是否已經發生。

is_set()

???? 當且僅當Event對象內部維護的flag為True時,返回True,否則返回False

set()

????將flag置為True

clear()

????將flag置為False

wait(timeout=-1)

????當flag是False時,阻塞;一旦為True或超時,立刻喚醒

舉個例子,好比像心意女生表白:

#! /usr/bin/python # _*_ coding: utf-8 _*_ __author__ = 'Jeffery' __date__ = '2018/9/15 14:58'import threading import timeevent = threading.Event()# 假設你想表白某位心儀女孩 # 你想,表白時送點花,更有氣氛,于是乎你打電話去花店,叫老板送一束花過來 # 然后再表白def confess_to_girl():print('u r preparing to confess')event.wait()print('start to confess: hi , my loving girl, I....')def flower_delivering():print('flower is delivering, plea wait')time.sleep(5)print('flower comes')event.set()def main():t1 = threading.Thread(target=confess_to_girl)t2 = threading.Thread(target=flower_delivering)t1.start()t2.start()t1.join()t2.join()print('\nstory,maybe new start, maybe ending!')if __name__ == '__main__':main()

Timer對象

?計時器,即讓一個線程在一個指定的之間之后再開始執行,是屬于Thread的一個封裝子類,故用法基本相似。

def hello():print("hello, world")t = Timer(30.0, hello) # t.cancel() # 在開始之前,還可以使計時器停止 t.start() # after 30 seconds, "hello, world" will be printed

Barrier對象

??Barrier,顧名思義就是障礙的意思,只有人多力量大的時候,才能一起跨過一個個障礙,繼續前行。Barrier則是一個線程障礙,只有線程數量達到指定數量之后,才能喚醒所有等待進程。這個功能不是很常用,簡單介紹一下吧,主要方法有:

wait(timeout=None)

????使線程進入等待狀態,直到達到一定數量,這時將會使barrier進入broken狀態,從而一齊釋放被堵塞的線程

reset()

????使Barrier恢復默認‘攔截’狀態

abort()

????使Barrier進入Broken狀態

parties

????即上面提到的 指定數量的線程,int類型

n_waiting

????正在等待的線程

broken

????bool類型,指示Barrier是否處于Broken狀態

總結

以上是生活随笔為你收集整理的Python Threading 多线程编程的全部內容,希望文章能夠幫你解決所遇到的問題。

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