99999久久久久久亚洲,欧美人与禽猛交狂配,高清日韩av在线影院,一个人在线高清免费观看,啦啦啦在线视频免费观看www

熱線電話:13121318867

登錄
首頁精彩閱讀Python多線程與同步 (threading包)
Python多線程與同步 (threading包)
2017-04-17
收藏

Python多線程與同步 (threading包)

Python主要通過標準庫中的threading包來實現(xiàn)多線程。在當今網(wǎng)絡(luò)時代,每個服務(wù)器都會接收到大量的請求。服務(wù)器可以利用多線程的方式來處理這些請求,以提高對網(wǎng)絡(luò)端口的讀寫效率。Python是一種網(wǎng)絡(luò)服務(wù)器的后臺工作語言 (比如豆瓣網(wǎng)),所以多線程也就很自然被Python語言支持。
(關(guān)于多線程的原理和C實現(xiàn)方法,請參考我之前寫的Linux多線程與同步,要了解race condition, mutex和condition variable的概念)
多線程售票以及同步
我們使用Python來實現(xiàn)Linux多線程與同步文中的售票程序。我們使用mutex (也就是Python中的Lock類對象) 來實現(xiàn)線程的同步:
# A program to simulate selling tickets in multi-thread way
# Written by Vamei

import threading
import time
import os

# This function could be any function to do other chores.
def doChore():
    time.sleep(0.5)

# Function for each thread
def booth(tid):
    global i
    global lock
    while True:
        lock.acquire()                # Lock; or wait if other thread is holding the lock
        if i != 0:
            i = i - 1                 # Sell tickets
            print(tid,':now left:',i) # Tickets left
            doChore()                 # Other critical operations
        else:
            print("Thread_id",tid," No more tickets")
            os._exit(0)              # Exit the whole process immediately
        lock.release()               # Unblock
        doChore()                    # Non-critical operations

# Start of the main function
i    = 100                           # Available ticket number
lock = threading.Lock()              # Lock (i.e., mutex)

# Start 10 threads
for k in range(10):
    new_thread = threading.Thread(target=booth,args=(k,))   # Set up thread; target: the callable (function) to be run, args: the argument for the callable
    new_thread.start()                                      # run the thread
我們使用了兩個全局變量,一個是i,用以儲存剩余票數(shù);一個是lock對象,用于同步線程對i的修改。此外,在最后的for循環(huán)中,我們總共設(shè)置了10個線程。每個線程都執(zhí)行booth()函數(shù)。線程在調(diào)用start()方法的時候正式啟動 (實際上,計算機中最多會有11個線程,因為主程序本身也會占用一個線程)。Python使用threading.Thread對象來代表線程,用threading.Lock對象來代表一個互斥鎖 (mutex)。
有兩點需要注意:
    我們在函數(shù)中使用global來聲明變量為全局變量,從而讓多線程共享i和lock (在C語言中,我們通過將變量放在所有函數(shù)外面來讓它成為全局變量)。如果不這么聲明,由于i和lock是不可變數(shù)據(jù)對象,它們將被當作一個局部變量(參看Python動態(tài)類型)。如果是可變數(shù)據(jù)對象的話,則不需要global聲明。我們甚至可以將可變數(shù)據(jù)對象作為參數(shù)來傳遞給線程函數(shù)。這些線程將共享這些可變數(shù)據(jù)對象。
    我們在booth中使用了兩個doChore()函數(shù)??梢栽谖磥砀倪M程序,以便讓線程除了進行i=i-1之外,做更多的操作,比如打印剩余票數(shù),找錢,或者喝口水之類的。第一個doChore()依然在Lock內(nèi)部,所以可以安全地使用共享資源 (critical operations, 比如打印剩余票數(shù))。第二個doChore()時,Lock已經(jīng)被釋放,所以不能再去使用共享資源。這時候可以做一些不使用共享資源的操作 (non-critical operation, 比如找錢、喝水)。我故意讓doChore()等待了0.5秒,以代表這些額外的操作可能花費的時間。你可以定義的函數(shù)來代替doChore()。
OOP創(chuàng)建線程
上面的Python程序非常類似于一個面向過程的C程序。我們下面介紹如何通過面向?qū)ο?(OOP, object-oriented programming,參看Python面向?qū)ο蟮幕靖拍詈蚉ython面向?qū)ο蟮倪M一步拓展) 的方法實現(xiàn)多線程,其核心是繼承threading.Thread類。我們上面的for循環(huán)中已經(jīng)利用了threading.Thread()的方法來創(chuàng)建一個Thread對象,并將函數(shù)booth()以及其參數(shù)傳遞給改對象,并調(diào)用start()方法來運行線程。OOP的話,通過修改Thread類的run()方法來定義線程所要執(zhí)行的命令。
復(fù)制代碼

# A program to simulate selling tickets in multi-thread way
# Written by Vamei

import threading
import time
import os

# This function could be any function to do other chores.
def doChore():
    time.sleep(0.5)

# Function for each thread
class BoothThread(threading.Thread):
    def __init__(self, tid, monitor):
        self.tid          = tid
        self.monitor = monitor
        threading.Thread.__init__(self)
    def run(self):
        while True:
            monitor['lock'].acquire()                          # Lock; or wait if other thread is holding the lock
            if monitor['tick'] != 0:
                monitor['tick'] = monitor['tick'] - 1          # Sell tickets
                print(self.tid,':now left:',monitor['tick'])   # Tickets left
                doChore()                                      # Other critical operations
            else:
                print("Thread_id",self.tid," No more tickets")
                os._exit(0)                                    # Exit the whole process immediately
            monitor['lock'].release()                          # Unblock
            doChore()                                          # Non-critical operations

# Start of the main function
monitor = {'tick':100, 'lock':threading.Lock()}

# Start 10 threads
for k in range(10):
    new_thread = BoothThread(k, monitor)
    new_thread.start()

復(fù)制代碼

我們自己定義了一個類BoothThread, 這個類繼承自thread.Threading類。然后我們把上面的booth()所進行的操作統(tǒng)統(tǒng)放入到BoothThread類的run()方法中。注意,我們沒有使用全局變量聲明global,而是使用了一個詞典monitor存放全局變量,然后把詞典作為參數(shù)傳遞給線程函數(shù)。由于詞典是可變數(shù)據(jù)對象,所以當它被傳遞給函數(shù)的時候,函數(shù)所使用的依然是同一個對象,相當于被多個線程所共享。這也是多線程乃至于多進程編程的一個技巧 (應(yīng)盡量避免上面的global聲明的用法,因為它并不適用于windows平臺)。

上面OOP編程方法與面向過程的編程方法相比,并沒有帶來太大實質(zhì)性的差別。

 
其他

threading.Thread對象: 我們已經(jīng)介紹了該對象的start()和run(), 此外:

    join()方法,調(diào)用該方法的線程將等待直到改Thread對象完成,再恢復(fù)運行。這與進程間調(diào)用wait()函數(shù)相類似。

 

下面的對象用于處理多線程同步。對象一旦被建立,可以被多個線程共享,并根據(jù)情況阻塞某些進程。請與Linux多線程與同步中的同步工具參照閱讀。

threading.Lock對象: mutex, 有acquire()和release()方法。

threading.Condition對象: condition variable,建立該對象時,會包含一個Lock對象 (因為condition variable總是和mutex一起使用)??梢詫ondition對象調(diào)用acquire()和release()方法,以控制潛在的Lock對象。此外:

    wait()方法,相當于cond_wait()
    notify_all(),相當與cond_broadcast()
    nofify(),與notify_all()功能類似,但只喚醒一個等待的線程,而不是全部

threading.Semaphore對象: semaphore,也就是計數(shù)鎖(semaphore傳統(tǒng)意義上是一種進程間同步工具,見Linux進程間通信)。創(chuàng)建對象的時候,可以傳遞一個整數(shù)作為計數(shù)上限 (sema = threading.Semaphore(5))。它與Lock類似,也有Lock的兩個方法。數(shù)據(jù)分析師培訓(xùn)
threading.Event對象: 與threading.Condition相類似,相當于沒有潛在的Lock保護的condition variable。對象有True和False兩個狀態(tài)。可以多個線程使用wait()等待,直到某個線程調(diào)用該對象的set()方法,將對象設(shè)置為True。線程可以調(diào)用對象的clear()方法來重置對象為False狀態(tài)。

數(shù)據(jù)分析咨詢請掃描二維碼

若不方便掃碼,搜微信號:CDAshujufenxi

數(shù)據(jù)分析師資訊
更多

OK
客服在線
立即咨詢
客服在線
立即咨詢
') } function initGt() { var handler = function (captchaObj) { captchaObj.appendTo('#captcha'); captchaObj.onReady(function () { $("#wait").hide(); }).onSuccess(function(){ $('.getcheckcode').removeClass('dis'); $('.getcheckcode').trigger('click'); }); window.captchaObj = captchaObj; }; $('#captcha').show(); $.ajax({ url: "/login/gtstart?t=" + (new Date()).getTime(), // 加隨機數(shù)防止緩存 type: "get", dataType: "json", success: function (data) { $('#text').hide(); $('#wait').show(); // 調(diào)用 initGeetest 進行初始化 // 參數(shù)1:配置參數(shù) // 參數(shù)2:回調(diào),回調(diào)的第一個參數(shù)驗證碼對象,之后可以使用它調(diào)用相應(yīng)的接口 initGeetest({ // 以下 4 個配置參數(shù)為必須,不能缺少 gt: data.gt, challenge: data.challenge, offline: !data.success, // 表示用戶后臺檢測極驗服務(wù)器是否宕機 new_captcha: data.new_captcha, // 用于宕機時表示是新驗證碼的宕機 product: "float", // 產(chǎn)品形式,包括:float,popup width: "280px", https: true // 更多配置參數(shù)說明請參見:http://docs.geetest.com/install/client/web-front/ }, handler); } }); } function codeCutdown() { if(_wait == 0){ //倒計時完成 $(".getcheckcode").removeClass('dis').html("重新獲取"); }else{ $(".getcheckcode").addClass('dis').html("重新獲取("+_wait+"s)"); _wait--; setTimeout(function () { codeCutdown(); },1000); } } function inputValidate(ele,telInput) { var oInput = ele; var inputVal = oInput.val(); var oType = ele.attr('data-type'); var oEtag = $('#etag').val(); var oErr = oInput.closest('.form_box').next('.err_txt'); var empTxt = '請輸入'+oInput.attr('placeholder')+'!'; var errTxt = '請輸入正確的'+oInput.attr('placeholder')+'!'; var pattern; if(inputVal==""){ if(!telInput){ errFun(oErr,empTxt); } return false; }else { switch (oType){ case 'login_mobile': pattern = /^1[3456789]\d{9}$/; if(inputVal.length==11) { $.ajax({ url: '/login/checkmobile', type: "post", dataType: "json", data: { mobile: inputVal, etag: oEtag, page_ur: window.location.href, page_referer: document.referrer }, success: function (data) { } }); } break; case 'login_yzm': pattern = /^\d{6}$/; break; } if(oType=='login_mobile'){ } if(!!validateFun(pattern,inputVal)){ errFun(oErr,'') if(telInput){ $('.getcheckcode').removeClass('dis'); } }else { if(!telInput) { errFun(oErr, errTxt); }else { $('.getcheckcode').addClass('dis'); } return false; } } return true; } function errFun(obj,msg) { obj.html(msg); if(msg==''){ $('.login_submit').removeClass('dis'); }else { $('.login_submit').addClass('dis'); } } function validateFun(pat,val) { return pat.test(val); }