python中怎么利用threading實(shí)現(xiàn)多線程

python中怎么利用threading實(shí)現(xiàn)多線程,很多新手對此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

創(chuàng)新互聯(lián)公司是少有的成都做網(wǎng)站、網(wǎng)站設(shè)計(jì)、營銷型企業(yè)網(wǎng)站、小程序制作、手機(jī)APP,開發(fā)、制作、設(shè)計(jì)、買友情鏈接、推廣優(yōu)化一站式服務(wù)網(wǎng)絡(luò)公司,公司2013年成立,堅(jiān)持透明化,價(jià)格低,無套路經(jīng)營理念。讓網(wǎng)頁驚喜每一位訪客多年來深受用戶好評

threading用于提供線程相關(guān)的操作,線程是應(yīng)用程序中工作的最小單元。python當(dāng)前版本的多線程庫沒有實(shí)現(xiàn)優(yōu)先級、線程組,線程也不能被停止、暫停、恢復(fù)、中斷。

threading模塊提供的類: 
  Thread, Lock, Rlock, Condition, [Bounded]Semaphore, Event, Timer, local。

threading 模塊提供的常用方法: 
  threading.currentThread(): 返回當(dāng)前的線程變量。 
  threading.enumerate(): 返回一個(gè)包含正在運(yùn)行的線程的list。正在運(yùn)行指線程啟動(dòng)后、結(jié)束前,不包括啟動(dòng)前和終止后的線程。 
  threading.activeCount(): 返回正在運(yùn)行的線程數(shù)量,與len(threading.enumerate())有相同的結(jié)果。

threading 模塊提供的常量:

threading.TIMEOUT_MAX 設(shè)置threading全局超時(shí)時(shí)間。

Thread類

Thread是線程類,有兩種使用方法,直接傳入要運(yùn)行的方法或從Thread繼承并覆蓋run():

# coding:utf-8
import threading
import time
#方法一:將要執(zhí)行的方法作為參數(shù)傳給Thread的構(gòu)造方法
def action(arg):
    time.sleep(1)
    print 'the arg is:%s\r' %arg

for i in xrange(4):
    t =threading.Thread(target=action,args=(i,))
    t.start()

print 'main thread end!'

#方法二:從Thread繼承,并重寫run()
class MyThread(threading.Thread):
    def __init__(self,arg):
        super(MyThread, self).__init__()#注意:一定要顯式的調(diào)用父類的初始化函數(shù)。
        self.arg=arg
    def run(self):#定義每個(gè)線程要運(yùn)行的函數(shù)
        time.sleep(1)
        print 'the arg is:%s\r' % self.arg

for i in xrange(4):
    t =MyThread(i)
    t.start()

print 'main thread end!'

構(gòu)造方法:
Thread(group=None, target=None, name=None, args=(), kwargs={}) 

group: 線程組,目前還沒有實(shí)現(xiàn),庫引用中提示必須是None; 
  target: 要執(zhí)行的方法; 
  name: 線程名; 
  args/kwargs: 要傳入方法的參數(shù)。

實(shí)例方法:
  isAlive(): 返回線程是否在運(yùn)行。正在運(yùn)行指啟動(dòng)后、終止前。 
  get/setName(name): 獲取/設(shè)置線程名。 

start():  線程準(zhǔn)備就緒,等待CPU調(diào)度
  is/setDaemon(bool): 獲取/設(shè)置是后臺線程(默認(rèn)前臺線程(False))。(在start之前設(shè)置)

如果是后臺線程,主線程執(zhí)行過程中,后臺線程也在進(jìn)行,主線程執(zhí)行完畢后,后臺線程不論成功與否,主線程和后臺線程均停止
         如果是前臺線程,主線程執(zhí)行過程中,前臺線程也在進(jìn)行,主線程執(zhí)行完畢后,等待前臺線程也執(zhí)行完成后,程序停止
  start(): 啟動(dòng)線程。 
  join([timeout]): 阻塞當(dāng)前上下文環(huán)境的線程,直到調(diào)用此方法的線程終止或到達(dá)指定的timeout(可選參數(shù))。

使用例子一(未設(shè)置setDeamon): 

# coding:utf-8
import threading
import time

def action(arg):
    time.sleep(1)
    print  'sub thread start!the thread name is:%s\r' % threading.currentThread().getName()
    print 'the arg is:%s\r' %arg
    time.sleep(1)

for i in xrange(4):
    t =threading.Thread(target=action,args=(i,))
    t.start()

print 'main_thread end!'
main_thread end!
sub thread start!the thread name is:Thread-2
the arg is:1
the arg is:0
sub thread start!the thread name is:Thread-4
the arg is:2
the arg is:3
Process finished with exit code 0
可以看出,創(chuàng)建的4個(gè)“前臺”線程,主線程執(zhí)行過程中,前臺線程也在進(jìn)行,主線程執(zhí)行完畢后,等待前臺線程也執(zhí)行完成后,程序停止

驗(yàn)證了serDeamon(False)(默認(rèn))前臺線程,主線程執(zhí)行過程中,前臺線程也在進(jìn)行,主線程執(zhí)行完畢后,等待前臺線程也執(zhí)行完成后,主線程停止。

使用例子二(setDeamon=True)

# coding:utf-8
import threading
import time

def action(arg):
    time.sleep(1)
    print  'sub thread start!the thread name is:%s\r' % threading.currentThread().getName()
    print 'the arg is:%s\r' %arg
    time.sleep(1)

for i in xrange(4):
    t =threading.Thread(target=action,args=(i,))
    t.setDaemon(True)#設(shè)置線程為后臺線程
    t.start()

print 'main_thread end!'
main_thread end!

Process finished with exit code 0

可以看出,主線程執(zhí)行完畢后,后臺線程不管是成功與否,主線程均停止

驗(yàn)證了serDeamon(True)后臺線程,主線程執(zhí)行過程中,后臺線程也在進(jìn)行,主線程執(zhí)行完畢后,后臺線程不論成功與否,主線程均停止。

使用例子三(設(shè)置join)

#coding:utf-8
import threading
import time

def action(arg):
    time.sleep(1)
    print  'sub thread start!the thread name is:%s    ' % threading.currentThread().getName()
    print 'the arg is:%s   ' %arg
    time.sleep(1)

thread_list = []    #線程存放列表
for i in xrange(4):
    t =threading.Thread(target=action,args=(i,))
    t.setDaemon(True)
    thread_list.append(t)

for t in thread_list:
    t.start()

for t in thread_list:
    t.join()
sub thread start!the thread name is:Thread-2    
the arg is:1   
sub thread start!the thread name is:Thread-3    
the arg is:2   
sub thread start!the thread name is:Thread-1    
the arg is:0   
sub thread start!the thread name is:Thread-4    
the arg is:3   
main_thread end!

Process finished with exit code 0

設(shè)置join之后,主線程等待子線程全部執(zhí)行完成后或者子線程超時(shí)后,主線程才結(jié)束

驗(yàn)證了 join()阻塞當(dāng)前上下文環(huán)境的線程,直到調(diào)用此方法的線程終止或到達(dá)指定的timeout,即使設(shè)置了setDeamon(True)主線程依然要等待子線程結(jié)束。

使用例子四(join不妥當(dāng)?shù)挠梅?,使多線程編程順序執(zhí)行)

#coding:utf-8
import threading
import time

def action(arg):
    time.sleep(1)
    print  'sub thread start!the thread name is:%s    ' % threading.currentThread().getName()
    print 'the arg is:%s   ' %arg
    time.sleep(1)


for i in xrange(4):
    t =threading.Thread(target=action,args=(i,))
    t.setDaemon(True)
    t.start()
    t.join()

print 'main_thread end!'
sub thread start!the thread name is:Thread-1    
the arg is:0   
sub thread start!the thread name is:Thread-2    
the arg is:1   
sub thread start!the thread name is:Thread-3    
the arg is:2   
sub thread start!the thread name is:Thread-4    
the arg is:3   
main_thread end!

Process finished with exit code 0
可以看出此時(shí),程序只能順序執(zhí)行,每個(gè)線程都被上一個(gè)線程的join阻塞,使得“多線程”失去了多線程意義。

Lock、Rlock類

由于線程之間隨機(jī)調(diào)度:某線程可能在執(zhí)行n條后,CPU接著執(zhí)行其他線程。為了多個(gè)線程同時(shí)操作一個(gè)內(nèi)存中的資源時(shí)不產(chǎn)生混亂,我們使用鎖。

Lock(指令鎖)是可用的最低級的同步指令。Lock處于鎖定狀態(tài)時(shí),不被特定的線程擁有。Lock包含兩種狀態(tài)——鎖定和非鎖定,以及兩個(gè)基本的方法。

可以認(rèn)為Lock有一個(gè)鎖定池,當(dāng)線程請求鎖定時(shí),將線程至于池中,直到獲得鎖定后出池。池中的線程處于狀態(tài)圖中的同步阻塞狀態(tài)。

RLock(可重入鎖)是一個(gè)可以被同一個(gè)線程請求多次的同步指令。RLock使用了“擁有的線程”和“遞歸等級”的概念,處于鎖定狀態(tài)時(shí),RLock被某個(gè)線程擁有。擁有RLock的線程可以再次調(diào)用acquire(),釋放鎖時(shí)需要調(diào)用release()相同次數(shù)。

可以認(rèn)為RLock包含一個(gè)鎖定池和一個(gè)初始值為0的計(jì)數(shù)器,每次成功調(diào)用 acquire()/release(),計(jì)數(shù)器將+1/-1,為0時(shí)鎖處于未鎖定狀態(tài)。

簡言之:Lock屬于全局,Rlock屬于線程。

構(gòu)造方法:
Lock(),Rlock(),推薦使用Rlock()

實(shí)例方法:
  acquire([timeout]): 嘗試獲得鎖定。使線程進(jìn)入同步阻塞狀態(tài)。 
  release(): 釋放鎖。使用前線程必須已獲得鎖定,否則將拋出異常。

例子一(未使用鎖):

#coding:utf-8
import threading
import time

gl_num = 0

def show(arg):
    global gl_num
    time.sleep(1)
    gl_num +=1
    print gl_num

for i in range(10):
    t = threading.Thread(target=show, args=(i,))
    t.start()

print 'main thread stop'
main thread stop
12

 3
4
568
 9

910


Process finished with exit code 0

多次運(yùn)行可能產(chǎn)生混亂。這種場景就是適合使用鎖的場景。

例子二(使用鎖):

# coding:utf-8

import threading
import time

gl_num = 0

lock = threading.RLock()


# 調(diào)用acquire([timeout])時(shí),線程將一直阻塞,
# 直到獲得鎖定或者直到timeout秒后(timeout參數(shù)可選)。
# 返回是否獲得鎖。
def Func():
    lock.acquire()
    global gl_num
    gl_num += 1
    time.sleep(1)
    print gl_num
    lock.release()


for i in range(10):
    t = threading.Thread(target=Func)
    t.start()
1
2
3
4
5
6
7
8
9
10

Process finished with exit code 0
可以看出,全局變量在在每次被調(diào)用時(shí)都要獲得鎖,才能操作,因此保證了共享數(shù)據(jù)的安全性

Lock對比Rlock

#coding:utf-8

import threading

lock = threading.Lock() #Lock對象

lock.acquire()

lock.acquire()  #產(chǎn)生了死鎖。

lock.release()

lock.release()

print lock.acquire()

import threading

rLock = threading.RLock()  #RLock對象

rLock.acquire()

rLock.acquire() #在同一線程內(nèi),程序不會(huì)堵塞。

rLock.release()

rLock.release()

Condition類

Condition(條件變量)通常與一個(gè)鎖關(guān)聯(lián)。需要在多個(gè)Contidion中共享一個(gè)鎖時(shí),可以傳遞一個(gè)Lock/RLock實(shí)例給構(gòu)造方法,否則它將自己生成一個(gè)RLock實(shí)例。

可以認(rèn)為,除了Lock帶有的鎖定池外,Condition還包含一個(gè)等待池,池中的線程處于等待阻塞狀態(tài),直到另一個(gè)線程調(diào)用notify()/notifyAll()通知;得到通知后線程進(jìn)入鎖定池等待鎖定。

構(gòu)造方法:
Condition([lock/rlock])

實(shí)例方法:
  acquire([timeout])/release(): 調(diào)用關(guān)聯(lián)的鎖的相應(yīng)方法。 
  wait([timeout]): 調(diào)用這個(gè)方法將使線程進(jìn)入Condition的等待池等待通知,并釋放鎖。使用前線程必須已獲得鎖定,否則將拋出異常。 
  notify(): 調(diào)用這個(gè)方法將從等待池挑選一個(gè)線程并通知,收到通知的線程將自動(dòng)調(diào)用acquire()嘗試獲得鎖定(進(jìn)入鎖定池);其他線程仍然在等待池中。調(diào)用這個(gè)方法不會(huì)釋放鎖定。使用前線程必須已獲得鎖定,否則將拋出異常。 
  notifyAll(): 調(diào)用這個(gè)方法將通知等待池中所有的線程,這些線程都將進(jìn)入鎖定池嘗試獲得鎖定。調(diào)用這個(gè)方法不會(huì)釋放鎖定。使用前線程必須已獲得鎖定,否則將拋出異常。

例子一:生產(chǎn)者消費(fèi)者模型

# encoding: UTF-8
import threading
import time

# 商品
product = None
# 條件變量
con = threading.Condition()


# 生產(chǎn)者方法
def produce():
    global product

    if con.acquire():
        while True:
            if product is None:
                print 'produce...'
                product = 'anything'

                # 通知消費(fèi)者,商品已經(jīng)生產(chǎn)
                con.notify()

            # 等待通知
            con.wait()
            time.sleep(2)


# 消費(fèi)者方法
def consume():
    global product

    if con.acquire():
        while True:
            if product is not None:
                print 'consume...'
                product = None

                # 通知生產(chǎn)者,商品已經(jīng)沒了
                con.notify()

            # 等待通知
            con.wait()
            time.sleep(2)


t1 = threading.Thread(target=produce)
t2 = threading.Thread(target=consume)
t2.start()
t1.start()
produce...
consume...
produce...
consume...
produce...
consume...
produce...
consume...
produce...
consume...

Process finished with exit code -1
程序不斷循環(huán)運(yùn)行下去。重復(fù)生產(chǎn)消費(fèi)過程。

例子二:生產(chǎn)者消費(fèi)者模型

import threading
import time

condition = threading.Condition()
products = 0

class Producer(threading.Thread):
    def run(self):
        global products
        while True:
            if condition.acquire():
                if products < 10:
                    products += 1;
                    print "Producer(%s):deliver one, now products:%s" %(self.name, products)
                    condition.notify()#不釋放鎖定,因此需要下面一句
                    condition.release()
                else:
                    print "Producer(%s):already 10, stop deliver, now products:%s" %(self.name, products)
                    condition.wait();#自動(dòng)釋放鎖定
                time.sleep(2)

class Consumer(threading.Thread):
    def run(self):
        global products
        while True:
            if condition.acquire():
                if products > 1:
                    products -= 1
                    print "Consumer(%s):consume one, now products:%s" %(self.name, products)
                    condition.notify()
                    condition.release()
                else:
                    print "Consumer(%s):only 1, stop consume, products:%s" %(self.name, products)
                    condition.wait();
                time.sleep(2)

if __name__ == "__main__":
    for p in range(0, 2):
        p = Producer()
        p.start()

    for c in range(0, 3):
        c = Consumer()
        c.start()

例子三:

import threading
 
alist = None
condition = threading.Condition()
 
def doSet():
    if condition.acquire():
        while alist is None:
            condition.wait()
        for i in range(len(alist))[::-1]:
            alist[i] = 1
        condition.release()
 
def doPrint():
    if condition.acquire():
        while alist is None:
            condition.wait()
        for i in alist:
            print i,
        print
        condition.release()
 
def doCreate():
    global alist
    if condition.acquire():
        if alist is None:
            alist = [0 for i in range(10)]
            condition.notifyAll()
        condition.release()
 
tset = threading.Thread(target=doSet,name='tset')
tprint = threading.Thread(target=doPrint,name='tprint')
tcreate = threading.Thread(target=doCreate,name='tcreate')
tset.start()
tprint.start()
tcreate.start()

Event類

Event(事件)是最簡單的線程通信機(jī)制之一:一個(gè)線程通知事件,其他線程等待事件。Event內(nèi)置了一個(gè)初始為False的標(biāo)志,當(dāng)調(diào)用set()時(shí)設(shè)為True,調(diào)用clear()時(shí)重置為 False。wait()將阻塞線程至等待阻塞狀態(tài)。

Event其實(shí)就是一個(gè)簡化版的 Condition。Event沒有鎖,無法使線程進(jìn)入同步阻塞狀態(tài)。

構(gòu)造方法:
Event()

實(shí)例方法:
  isSet(): 當(dāng)內(nèi)置標(biāo)志為True時(shí)返回True。 
  set(): 將標(biāo)志設(shè)為True,并通知所有處于等待阻塞狀態(tài)的線程恢復(fù)運(yùn)行狀態(tài)。 
  clear(): 將標(biāo)志設(shè)為False。 
  wait([timeout]): 如果標(biāo)志為True將立即返回,否則阻塞線程至等待阻塞狀態(tài),等待其他線程調(diào)用set()。

例子一

# encoding: UTF-8
import threading
import time

event = threading.Event()


def func():
    # 等待事件,進(jìn)入等待阻塞狀態(tài)
    print '%s wait for event...' % threading.currentThread().getName()
    event.wait()

    # 收到事件后進(jìn)入運(yùn)行狀態(tài)
    print '%s recv event.' % threading.currentThread().getName()


t1 = threading.Thread(target=func)
t2 = threading.Thread(target=func)
t1.start()
t2.start()

time.sleep(2)

# 發(fā)送事件通知
print 'MainThread set event.'
event.set()
Thread-1 wait for event...
Thread-2 wait for event...

#2秒后。。。
MainThread set event.
Thread-1 recv event.
 Thread-2 recv event.

Process finished with exit code 0

timer類

Timer(定時(shí)器)是Thread的派生類,用于在指定時(shí)間后調(diào)用一個(gè)方法。

構(gòu)造方法:
Timer(interval, function, args=[], kwargs={}) 
  interval: 指定的時(shí)間 
  function: 要執(zhí)行的方法 
  args/kwargs: 方法的參數(shù)

實(shí)例方法:
Timer從Thread派生,沒有增加實(shí)例方法。

例子一:

# encoding: UTF-8
import threading


def func():
    print 'hello timer!'


timer = threading.Timer(5, func)
timer.start()

線程延遲5秒后執(zhí)行。

local類

local是一個(gè)小寫字母開頭的類,用于管理 thread-local(線程局部的)數(shù)據(jù)。對于同一個(gè)local,線程無法訪問其他線程設(shè)置的屬性;線程設(shè)置的屬性不會(huì)被其他線程設(shè)置的同名屬性替換。

可以把local看成是一個(gè)“線程-屬性字典”的字典,local封裝了從自身使用線程作為 key檢索對應(yīng)的屬性字典、再使用屬性名作為key檢索屬性值的細(xì)節(jié)。

# encoding: UTF-8
import threading
 
local = threading.local()
local.tname = 'main'
 
def func():
    local.tname = 'notmain'
    print local.tname
 
t1 = threading.Thread(target=func)
t1.start()
t1.join()
 
print local.tname
notmain
main

看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對創(chuàng)新互聯(lián)的支持。

當(dāng)前名稱:python中怎么利用threading實(shí)現(xiàn)多線程
文章轉(zhuǎn)載:http://muchs.cn/article14/gddcge.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站建設(shè)、企業(yè)建站、小程序開發(fā)、虛擬主機(jī)、外貿(mào)網(wǎng)站建設(shè)、網(wǎng)站收錄

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站建設(shè)