铁乐学python_Day42_锁和队列
鐵樂學python_Day42_鎖和隊列
例:多個線程搶占資源的情況 from threading import Thread import timedef work():global ntemp = ntime.sleep(0.1)n = temp - 1if __name__ == '__main__':n = 100l = []for i in range(100):p = Thread(target=work)l.append(p)p.start()for p in l:p.join()print(n) # 很有可能n=99這個時候為了保障數據的安全,我們可以對公共數據使用鎖鎖起來。 import threading R=threading.Lock() R.acquire() ''' 對公共數據的操作 ''' R.release()例:加鎖同步數據 from threading import Thread,Lock import timedef work():global nlock.acquire()temp=ntime.sleep(0.1)n=temp-1lock.release()if __name__ == '__main__':lock=Lock()n=100l=[]for i in range(100):p=Thread(target=work)l.append(p)p.start()for p in l:p.join()print(n) #結果肯定為0,由原來的并發執行變成串行,犧牲了執行效率保證了數據安全。例:互斥鎖與join的區別 #不加鎖:并發執行,速度快,數據不安全 from threading import current_thread,Thread,Lock import time def task():global nprint('%s is running' %current_thread().getName())temp=ntime.sleep(0.5)n=temp-1if __name__ == '__main__':n=100lock=Lock()threads=[]start_time=time.time()for i in range(100):t=Thread(target=task)threads.append(t)t.start()for t in threads:t.join()stop_time=time.time()print('主:%s n:%s' %(stop_time-start_time,n))''' Thread-1 is running Thread-2 is running ...... Thread-100 is running 主:0.5216062068939209 n:99 '''#部分數據加上同步鎖:未加鎖部分并發執行,加鎖部分串行執行,速度慢,數據安全。 from threading import current_thread,Thread,Lock import time def task():#未加鎖的代碼并發運行time.sleep(3)print('%s start to run' %current_thread().getName())global n#加鎖的代碼串行運行lock.acquire()temp=ntime.sleep(0.5)n=temp-1lock.release()if __name__ == '__main__':n=100lock=Lock()threads=[]start_time=time.time()for i in range(100):t=Thread(target=task)threads.append(t)t.start()for t in threads:t.join()stop_time=time.time()print('主:%s n:%s' %(stop_time-start_time,n))''' Thread-1 is running Thread-2 is running ...... Thread-100 is running 主:53.294203758239746 n:0 '''#加鎖會讓運行變成串行,而在start之后立即使用join,不用加鎖了也是串行的效果。那么為什么使用加鎖呢? #在start之后立刻使用jion,也會將100個任務的執行變成串行,最終n的結果是0,也是安全的, #但問題是start后立即join:任務內的所有代碼都是串行執行的, #而加鎖,只是加鎖的部分即修改共享數據的部分是串行的, #單從保證數據安全方面,二者都可以實現,但很明顯是加鎖的效率更高.from threading import current_thread,Thread,Lock import time def task():time.sleep(3)print('%s start to run' %current_thread().getName())global ntemp=ntime.sleep(0.5)n=temp-1if __name__ == '__main__':n=100lock=Lock()start_time=time.time()for i in range(100):t=Thread(target=task)t.start()t.join()stop_time=time.time()print('主:%s n:%s' %(stop_time-start_time,n))''' Thread-1 start to run Thread-2 start to run ...... Thread-100 start to run 主:350.6937336921692 n:0 #耗時是多么的恐怖 '''死鎖與遞歸鎖死鎖與遞歸鎖
死鎖: 是指兩個或兩個以上的進程或線程在執行過程中,因爭奪資源而造成的一種互相等待的現象。
若無外力作用,它們都將無法推進下去。
此時稱系統處于死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程。
解決方法,遞歸鎖.
在Python中為了支持在同一線程中多次請求同一資源,python提供了遞歸鎖RLock。
這個RLock內部維護著一個Lock和一個counter變量,counter記錄了acquire的次數,從而使得資源可以被多次require。
直到一個線程所有的acquire都被release,其他的線程才能獲得資源。
上面的例子如果使用RLock代替Lock,則不會發生死鎖:
線程隊列(queue隊列)
queue隊列 :使用import queue,用法與進程中使用Queue一樣。
隊列長度可為無限或者有限??赏ㄟ^Queue的構造函數的可選參數maxsize來設定隊列長度。
如果maxsize小于1就表示隊列長度無限。
調用隊列對象的put()方法在隊尾插入一個項目。
put()有兩個參數,第一個item為必需的,為插入項目的值;
第二個block為可選參數,默認為1。
如果隊列當前為空且block為1,put()方法就使調用線程暫停,直到空出一個數據單元。
如果block為0,put方法將引發Full異常。
調用隊列對象的get()方法從隊頭刪除并返回一個項目。
可選參數為block,默認為True。
如果隊列為空且block為True,get()就使調用線程暫停,直至有項目可用。
如果隊列為空且block為False,隊列將引發Empty異常。
python queue 模塊有三種隊列:
1)class queue.Queue(maxsize=0) #First In First Out [FIFO 類似于棧 先進先出] import queueq=queue.Queue() q.put('first') q.put('second') q.put('third')print(q.get()) print(q.get()) print(q.get()) ''' 結果(先進先出): first second third '''2)class queue.LifoQueue(maxsize=0) #Last In Fisrt Out [LIFO 類似于堆 后進先出]import queueq=queue.LifoQueue() q.put('first') q.put('second') q.put('third')print(q.get()) print(q.get()) print(q.get()) ''' 結果(后進先出): third second first '''class queue.PriorityQueue(maxsize=0) #存儲數據時可設置優先級的隊列 [優先級隊列 數字越小(優先級越高)越先取出]import queueq=queue.PriorityQueue() #put進入一個元組,元組的第一個元素是優先級(通常是數字,也可以是非數字之間的比較),數字越小優先級越高 q.put((20,'a')) q.put((10,'b')) q.put((30,'c'))print(q.get()) print(q.get()) print(q.get()) ''' 結果(數字越小優先級越高,優先級高的優先出隊): (10, 'b') (20, 'a') (30, 'c') '''隊列中的其它方法: Queue.full # 與maxsize大小對應 Queue.qsize() # 返回隊列的大小 Queue.empty() # 隊列若為空則返回True Queue.full() # 隊列若為滿則返回True Queue.join() # block(阻塞)直到queue被消費完畢,再執行后面的操作Queue.get([block[, timeout]]) # 獲取隊列,timeout等待時間 Queue.get_nowait() # 相當Queue.get(False) Queue.put(item) # 非阻塞 寫入隊列,timeout等待時間 Queue.put_nowait(item) # 相當Queue.put(item, False) Queue.task_done() # 在完成一項工作之后,Queue.task_done()函數向任務已經完成的隊列發送一個信號例:使用多線程完成隊列中的任務import queue import threading import time import randomq = queue.Queue(0) # 當有多個線程共享一個東西的時候就可以用它了 NUM_WORKERS = 3class MyThread(threading.Thread):def __init__(self, input, worktype):self._jobq = inputself._work_type = worktypethreading.Thread.__init__(self)def run(self):while True:if self._jobq.qsize() > 0:self._process_job(self._jobq.get(), self._work_type)else:breakdef _process_job(self, job, worktype):doJob(job, worktype)def doJob(job, worktype):time.sleep(random.random() * 3)print("doing", job, " worktype ", worktype)if __name__ == '__main__':print("begin....")for i in range(NUM_WORKERS * 2):q.put(i) # 放入到任務隊列中去print("job qsize:", q.qsize())for x in range(NUM_WORKERS):MyThread(q, x).start()運行效果: begin.... job qsize: 6 doing 2 worktype 2 doing 0 worktype 0 doing 1 worktype 1 doing 3 worktype 2 doing 5 worktype 1 doing 4 worktype 0end
參考:http://www.cnblogs.com/Eva-J/articles/8306047.html
轉載于:https://www.cnblogs.com/tielemao/p/9078182.html
總結
以上是生活随笔為你收集整理的铁乐学python_Day42_锁和队列的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 东莞新房备案价查询方法?
- 下一篇: Java8-Guava实战示例