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
殺掉進程的同時殺掉線程。(可以殺死進程,但是線程是無法殺掉的)