python threading模組線程鎖的例子

來源:互聯網
上載者:User


python threading模組有兩類鎖:互斥鎖(threading.Lock )和可重用鎖(threading.RLock)。兩者的用法基本相同,具體如下:

lock = threading.Lock()
lock.acquire()
dosomething……
lock.release()
RLock的用法是將threading.Lock()修改為threading.RLock()。便於理解,先來段代碼:

[root@361way lock]# cat lock1.py
#!/usr/bin/env python
# coding=utf-8
import threading                            # 匯入threading模組
import time                             # 匯入time模組
class mythread(threading.Thread):        # 通過繼承建立類
    def __init__(self,threadname):      # 初始化方法
        # 調用父類的初始化方法
        threading.Thread.__init__(self,name = threadname)
    def run(self):                          # 重載run方法
        global x                  # 使用global表明x為全域變數
        for i in range(3):
            x = x + 1
        time.sleep(5)          # 調用sleep函數,讓線程休眠5秒
        print x
tl = []                              # 定義列表
for i in range(10):
    t = mythread(str(i))               # 類執行個體化
    tl.append(t)                      # 將類對象添加到列表中
x=0                                 # 將x賦值為0
for i in tl:
    i.start() 
這裡執行的結果和想想的不同,結果如下:

[root@361way lock]# python lock1.py
30
30
30
30
30
30
30
30
30
30
為什麼結果都是30呢?關鍵在於global 行和 time.sleep行。

1、由於x是一個全域變數,所以每次迴圈後 x 的值都是執行後的結果值;

2、由於該代碼是多線程的操作,所以在sleep 等待的時候,之前已經執行完成的線程會在這等待,而後續的進程在等待的5秒這段時間也執行完成 ,等待print。同樣由於global 的原理,x被重新斌值。所以列印出的結果全是30 ;

3、便於理解,可以嘗試將sleep等注釋,你再看下結果,就會發現有不同。

在實際應用中,如抓取程式等,也會出現類似於sleep等待的情況。在前後調用有順序或列印有輸出的時候,就會現並發競爭,造成結果或輸出紊亂。這裡就引入了鎖的概念,上面的代碼修改下,如下:

[root@361way lock]# cat lock2.py
#!/usr/bin/env python
# coding=utf-8
import threading                            # 匯入threading模組
import time                             # 匯入time模組
class mythread(threading.Thread):                   # 通過繼承建立類
    def __init__(self,threadname):                  # 初始化方法
        threading.Thread.__init__(self,name = threadname)
    def run(self):                          # 重載run方法
        global x                        # 使用global表明x為全域變數
        lock.acquire()                      # 調用lock的acquire方法
        for i in range(3):
            x = x + 1
        time.sleep(5)           # 調用sleep函數,讓線程休眠5秒
        print x
        lock.release()                # 調用lock的release方法
lock = threading.Lock()               # 類執行個體化
tl = []                          # 定義列表
for i in range(10):
    t = mythread(str(i))            # 類執行個體化
    tl.append(t)              # 將類對象添加到列表中
x=0                        # 將x賦值為0
for i in tl:
    i.start()                     # 依次運行線程
執行的結果如下:

[root@361way lock]# python lock2.py
3
6
9
12
15
18
21
24
27
30
加鎖的結果會造成阻塞,而且會造成開鎖大。會根據順序由並發的多線程按順序輸出,如果後面的線程執行過快,需要等待前面的進程結束後其才能結束 --- 寫的貌似有點像隊列的概念了 ,不過在加鎖的很多情境下確實可以通過隊列去解決。

最後,再引入一個樣本,在股票量化分析(二)PE和流通市值篇中,介紹了如何採集stock的兩個指標,並按結果輸出,不過在輸出的時候發有會出現輸出紊亂,如下:

threading-lock

如600131和000708的stockid就輸出到了同一行,雖然通過多線程使執行速度快了很多 ,但這樣很不美觀,也不便於後續處理。

1、輸出競爭紊亂代碼

#!/usr/bin/python
#coding=utf-8
# 1、pe在 0~20 之間的企業
# 2、流通股本小於50億的企業
import urllib2
import time
import json
from threading import Thread
def get_pe(stockid):
    try:
        url = 'http://d.10jqka.com.cn/v2/realhead/hs_%s/last.js' % stockid
        send_headers = {
            'Host':'d.10jqka.com.cn',
            'Referer':'http://stock.10jqka.com.cn/',
            'Accept':'application/json, text/javascript, */*; q=0.01',
            'Connection':'keep-alive',
            'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36',
            'X-Forwarded-For':'124.160.148.178',
            'X-Requested-With':'XMLHttpRequest'
        }
        req = urllib2.Request(url,headers=send_headers)
        f = urllib2.urlopen(req)
        data = f.read().split('items":',1)[1]
        data = data.split('})',1)[0]
        J_data = json.loads(data)
        #J_data = json.dumps(data,indent=4,encoding='utf-8')
        stockpe = J_data['2034120']
        stockname = J_data['name']
        sumvalue = J_data['3475914']
        currentprice = J_data['10']
        #print stockid,stockname,stockpe
        return stockname,stockpe,sumvalue,currentprice
    except urllib2.HTTPError, e:
        #return stockid ,'get happed httperror'
        return e.code
def cond(stockid,pe,asset):
    pe = int(pe)
    asset = int(asset)
    try:
        stockname,stockpe,sumvalue,currentprice = get_pe(stockid)
        if sumvalue:
           Billvalue = round(float(sumvalue)/1000/1000/100)
        else:
           Billvalue = 0
        if stockpe:
           if float(stockpe) > 0 and float(stockpe) < pe and Billvalue < asset :
              print stockid,stockname,currentprice,stockpe,Billvalue
        #else:
        #   print stockid
    except TypeError ,e:
        print stockid ,'get is error'
if __name__ == '__main__':
    threads = []
    print 'stockid  stockname  currentprice  stockpe  Billvalue'
    stockids = [line.strip() for line in open("stock_exp.txt", 'r')]
    nloops = range(len(stockids))
    for stockid in stockids:
        t = Thread(target=cond, args=(stockid,28,80))
        threads.append(t)
    for i in nloops:
        threads[i].start()
    for i in nloops:
        threads[i].join()

2、加鎖後的代碼

#!/usr/bin/python
#coding=utf-8
# 1、pe在 0~20 之間的企業
# 2、流通股本小於50億的企業
import threading
import urllib2
import time
import json
lock = threading.Lock()
def get_pe(stockid):
    try:
        url = 'http://d.10jqka.com.cn/v2/realhead/hs_%s/last.js' % stockid
        send_headers = {
            'Host':'d.10jqka.com.cn',
            'Referer':'http://stock.10jqka.com.cn/',
            'Accept':'application/json, text/javascript, */*; q=0.01',
            'Connection':'keep-alive',
            'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36',
            'X-Forwarded-For':'124.160.148.178',
            'X-Requested-With':'XMLHttpRequest'
        }
        req = urllib2.Request(url,headers=send_headers)
        f = urllib2.urlopen(req)
        data = f.read().split('items":',1)[1]
        data = data.split('})',1)[0]
        J_data = json.loads(data)
        #J_data = json.dumps(data,indent=4,encoding='utf-8')
        stockpe = J_data['2034120']
        stockname = J_data['name']
        sumvalue = J_data['3475914']
        currentprice = J_data['10']
        #print stockid,stockname,stockpe
        return stockname,stockpe,sumvalue,currentprice
    except urllib2.HTTPError, e:
        #return stockid ,'get happed httperror'
        return e.code
def cond(stockid,pe,asset):
    pe = int(pe)
    asset = int(asset)
    try:
        stockname,stockpe,sumvalue,currentprice = get_pe(stockid)
        if sumvalue:
           Billvalue = round(float(sumvalue)/1000/1000/100)
        else:
           Billvalue = 0
        if stockpe:
           if float(stockpe) > 0 and float(stockpe) < pe and Billvalue < asset :
              lock.acquire()
              print stockid,stockname,currentprice,stockpe,Billvalue
              lock.release()
        #else:
        #   print stockid
    except TypeError ,e:
        print stockid ,'get is error'
if __name__ == '__main__':
    threads = []
    print 'stockid  stockname  currentprice  stockpe  Billvalue'
    stockids = [line.strip() for line in open("stock_exp.txt", 'r')]
    for stockid in stockids:
        t = threading.Thread(target=cond, args=(stockid,25,50))
        threads.append(t)
        t.start()

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.