python的多線程編程之鎖


1、 背景概述

在上篇文章中,主要講述了python中的socket編程的一些基本方面,但是缺少關於鎖的相關概念,從而在這篇文章中進行補充。


由於在python中,存在了GIL,也就是全局解釋器鎖,從而在每次進行獲得cpu的時候,同時只有一個線程獲得了cpu的運行,在這個方面可以認為是線程安全的,但是在線程運行的時候,是共享內存的,共享相同的數據信息,從而這個時候python的線程就不那么安全了。


在python中,要保證數據的正確性,並且自己對數據進行控制,對數據進行加鎖並且自己釋放鎖。


多線程的主要目的為了提高性能與速度,用在無關的方向是最好的,例如在使用爬蟲的時候,可以使用多線程來進行爬取數據,因為在這些線程之間沒有需要共同操作的數據,從而在這個時候利用是最好的。


如果需要操作同一份數據,那么必須自己保證數據的安全性。

如果需要利用多cpu的特性,那么應該使用的是多進程編程,而不是多線程編程,多進程編程為multiprocessing。


2、 利用鎖進行同步相同的數據

直接看以下的代碼:

#!/usr/bin/env python
import time
import threading

num = 0
class MyThread(threading.Thread):
    def run(self):
        #lock.acquire()
        #time.sleep(1)
        global num
        num += 1
        print self.name + 'set num to '+str(num)
        #lock.release()

#lock = threading.RLock()
threads = []
for i in range(10000):
    t = MyThread()
    threads.append(t)
for i in range(10000):
    threads[i].start()
for i in range(10000):
    threads[i].join()
看以上的代碼,對全局變量進行一個修改,從而每個線程取到的是同一份的數據,從而,可能造成數據的計算結果不正確,從而需要用鎖進行控制數據的正確性。


PS:在我的機器上進行運行的時候,都是正確的,從而看起來好像不用鎖也可以,但是在有的機器上進行模擬的時候,最后的計算結果不正確。


在使用鎖的時候,只要將注釋的代碼進行去掉即可使用鎖。

3、 鎖的類型

在python的threading模塊中,提供了三種鎖,如下所示:


在進行鎖的操作的時候,必須在每個線程中,自己獲取鎖,然后自己釋放鎖,否則會造成一直在等待,也可以稱之為死鎖。


4、 事件

在進行多線程的時候,可以判斷一個事件發生,然后觸發做另外的事情,從而可以使用event,如下代碼所示:

[root@python 523]# cat thread_demo.py 
#!/usr/bin/env python

import threading
import time
import Queue

def producter(name,queue,lock):
    event.clear()
    print '%s start to product...' % name
    queue.put('something')
    time.sleep(3)
    print 'product something'
    event.set()
    event.wait()

def consumer(name,queue,lock):
    print '%s start to consume...' % name
    event.wait()
    queue.get()
    print 'consume something'
    event.set()


lock = threading.Lock()
queue = Queue.Queue(10)
event = threading.Event()
threads = []
threadsc = []
for i in range(1):
    t = threading.Thread(target=producter,args=('kel%s' % i,queue,lock))
    threads.append(t)
for i in range(1):
    threads[i].start()
for i in range(1):
    t = threading.Thread(target=consumer,args=('smile%s' % i,queue,lock))
    threadsc.append(t)
for i in range(1):
    threadsc[i].start()

在使用event的時候,clear表示將flag設置為false,set表示設置為true,wait表示在false的時候,一直等待,從而當producter沒有數據的時候,consumer一直在等待。


這種可以做事件的觸發。


問題:

在進行此實驗的時候,如果線程出現錯誤,那么是無法關閉的,從而只有殺掉進程才可以,從而可以使用命令如下:

killall python

殺掉進程的同時殺掉線程。(可以殺死進程,但是線程是無法殺掉的)




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM