最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解python中的線(xiàn)程與線(xiàn)程池

 更新時(shí)間:2019年05月10日 12:03:08   作者:Makesths  
這篇文章主要介紹了python線(xiàn)程與線(xiàn)程池,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

線(xiàn)程

進(jìn)程和線(xiàn)程

什么是進(jìn)程?

進(jìn)程就是正在運(yùn)行的程序, 一個(gè)任務(wù)就是一個(gè)進(jìn)程, 進(jìn)程的主要工作是管理資源, 而不是實(shí)現(xiàn)功能

什么是線(xiàn)程?

線(xiàn)程的主要工作是去實(shí)現(xiàn)功能, 比如執(zhí)行計(jì)算.

線(xiàn)程和進(jìn)程的關(guān)系就像員工與老板的關(guān)系,

老板(進(jìn)程) 提供資源 和 工作空間,

員工(線(xiàn)程) 負(fù)責(zé)去完成相應(yīng)的任務(wù)

特點(diǎn)

一個(gè)進(jìn)程至少由一個(gè)線(xiàn)程, 這一個(gè)必須存在的線(xiàn)程被稱(chēng)為主線(xiàn)程, 同時(shí)一個(gè)進(jìn)程也可以有多個(gè)線(xiàn)程, 即多線(xiàn)程

當(dāng)我們我們遇到一些需要重復(fù)執(zhí)行的代碼時(shí), 就可以使用多線(xiàn)程分擔(dān)一些任務(wù), 進(jìn)而加快運(yùn)行速度

線(xiàn)程的實(shí)現(xiàn)

線(xiàn)程模塊

Python通過(guò)兩個(gè)標(biāo)準(zhǔn)庫(kù)_thread和threading, 提供對(duì)線(xiàn)程的支持 , threading對(duì)_thread進(jìn)行了封裝。
threading模塊中提供了Thread , Lock , RLock , Condition等組件。

因此在實(shí)際的使用中我們一般都是使用threading來(lái)實(shí)現(xiàn)多線(xiàn)程

線(xiàn)程包括子線(xiàn)程和主線(xiàn)程:

主線(xiàn)程 : 當(dāng)一個(gè)程序啟動(dòng)時(shí) , 就有一個(gè)線(xiàn)程開(kāi)始運(yùn)行 , 該線(xiàn)程通常叫做程序的主線(xiàn)程

子線(xiàn)程 : 因?yàn)槌绦蚴情_(kāi)始時(shí)就執(zhí)行的 , 如果你需要再創(chuàng)建線(xiàn)程 , 那么創(chuàng)建的線(xiàn)程就是這個(gè)主線(xiàn)程的子線(xiàn)程

主線(xiàn)程的重要性體現(xiàn)在兩方面 :

  1. 是產(chǎn)生其他子線(xiàn)程的線(xiàn)程
  2. 通常它必須最后完成執(zhí)行, 比如執(zhí)行各種關(guān)閉操作

Thread類(lèi)

常用參數(shù)說(shuō)明

參數(shù) 說(shuō)明
target 表示調(diào)用的對(duì)象, 即子線(xiàn)程要執(zhí)行的任務(wù), 可以是某個(gè)內(nèi)置方法, 或是你自己寫(xiě)的函數(shù)
name 子線(xiàn)程的名稱(chēng)
args 傳入target函數(shù)中的位置參數(shù), 是一個(gè)元組, 參數(shù)后必須加逗號(hào)

常用實(shí)例方法

方法 作用
Thread.run(self) 線(xiàn)程啟動(dòng)時(shí)運(yùn)行的方法, 由該方法調(diào)用 target參數(shù)所指定的函數(shù)
Thread.start(self) 啟動(dòng)進(jìn)程, start方法就是區(qū)幫你調(diào)用run方法
Thread.terminate(self) 強(qiáng)制終止線(xiàn)程
Thread.join(self, timeout=None) 阻塞調(diào)用, 主線(xiàn)程進(jìn)行等待
Thread.setDaemon(self, daemonic) 將子線(xiàn)程設(shè)置為守護(hù)線(xiàn)程, 隨主線(xiàn)程結(jié)束而結(jié)束
Thread.getName(self, name) 獲取線(xiàn)程名
Thread.setName(self, name) 設(shè)置線(xiàn)程名

創(chuàng)建線(xiàn)程

在python中創(chuàng)建線(xiàn)程有兩種方式, 實(shí)例Thread類(lèi)和繼承重寫(xiě)Thread類(lèi)

實(shí)例Thread類(lèi)

import threading
import time

def run(name, s): # 線(xiàn)程要執(zhí)行的任務(wù)
 time.sleep(s) # 停兩秒
 print('I am %s' % name)

# 實(shí)例化線(xiàn)程類(lèi), 并傳入函數(shù)及其參數(shù), 
t1 = threading.Thread(target=run, name='one', args=('One', 5))
t2 = threading.Thread(target=run, name='two', args=('Two', 2))

# 開(kāi)始執(zhí)行, 這兩個(gè)線(xiàn)程會(huì)同步執(zhí)行
t1.start()
t2.start()
print(t1.getName())		# 獲取線(xiàn)程名
print(t2.getName())

# Result:
one
two
I am Two	# 運(yùn)行2s后
I am One	# 運(yùn)行5s后

繼承Thread類(lèi)

class MyThread(threading.Thread): # 繼承threading中的Thread類(lèi)
 # 線(xiàn)程所需的參數(shù)
 def __init__(self, name, second):
 super().__init__()
 self.name = name
 self.second = second

 # 重寫(xiě)run方法,表示線(xiàn)程所執(zhí)行的任務(wù),必須有
 def run(self):
 time.sleep(self.second)
 print('I am %s' % self.name)
# 創(chuàng)建線(xiàn)程實(shí)例
t1 = MyThread('One', 5)
t2 = MyThread('Two', 2)
# 啟動(dòng)線(xiàn)程,實(shí)際上是調(diào)用了類(lèi)中的run方法
t1.start()
t2.start()
t1.join()
print(t1.getName())
print(t2.getName())

# Result:
I am Two	# 運(yùn)行后2s
I am One	# 運(yùn)行后5s
One
Two

常用方法

join()

阻塞調(diào)用程序 , 直到調(diào)用join () 方法的線(xiàn)程執(zhí)行結(jié)束, 才會(huì)繼續(xù)往下執(zhí)行

# 開(kāi)始執(zhí)行, 這兩個(gè)線(xiàn)程會(huì)同步執(zhí)行
t1.start()
t2.start()
t1.join()	# 等待t1線(xiàn)程執(zhí)行完畢,再繼續(xù)執(zhí)行剩余的代碼
print(t1.getName())
print(t2.getName())

# Result:	
I am Two
I am One
one
two

setDemon()

使用給線(xiàn)程設(shè)置守護(hù)模式: 子線(xiàn)程跟隨主線(xiàn)程的結(jié)束而結(jié)束, 不管這個(gè)子線(xiàn)程任務(wù)是否完成. 而非守護(hù)模式的子線(xiàn)程只有在執(zhí)行完成后, 主線(xiàn)程才會(huì)執(zhí)行完成

setDaemon() 與 join() 基本上是相對(duì)的 , join會(huì)等子線(xiàn)程執(zhí)行完畢 ; 而setDaemon則不會(huì)等

def run(name, s): # 線(xiàn)程要執(zhí)行的函數(shù)
 time.sleep(s) # 停兩秒
 print('I am %s' % name)

# 實(shí)例化線(xiàn)程類(lèi), 并傳入函數(shù)及其參數(shù)
t1 = threading.Thread(target=run, name='one', args=('One', 5))
t2 = threading.Thread(target=run, name='two', args=('Two', 2))
# 給t1設(shè)置守護(hù)模式, 使其隨著主線(xiàn)程的結(jié)束而結(jié)束
t1.setDaemon(True)
# 開(kāi)始執(zhí)行, 這兩個(gè)線(xiàn)程會(huì)同步執(zhí)行
t1.start()
t2.start()	# 主線(xiàn)程會(huì)等待未設(shè)置守護(hù)模式的線(xiàn)程t2執(zhí)行完成

# Result:
I am Two	# 運(yùn)行后2s

線(xiàn)程間的通信

互斥鎖

在同一個(gè)進(jìn)程的多線(xiàn)程中 , 其中的變量對(duì)于所有線(xiàn)程來(lái)說(shuō)都是共享的 , 因此 , 如果多個(gè)線(xiàn)程之間同時(shí)修改一個(gè)變量 , 那就亂套了 , 共享的數(shù)據(jù)就會(huì)有很大的風(fēng)險(xiǎn) , 所以我們需要互斥鎖 , 來(lái)鎖住數(shù)據(jù) , 防止篡改。

來(lái)看一個(gè)錯(cuò)誤的示范:

a = 0
def incr(n):
 global a
 for i in range(n):
 a += 1
# 這兩個(gè)方法同時(shí)聲明了變量a,并對(duì)其進(jìn)行修改
def decr(n):
 global a
 for i in range(n):
 a -= 1

t_incr = threading.Thread(target=incr, args=(1000000,))
t_decr = threading.Thread(target=decr, args=(1000000,))
t_incr.start()
t_decr.start()
t_incr.join()
t_decr.join()
print(a)
# 期望結(jié)果應(yīng)該是0, 但是因?yàn)檫@里沒(méi)有設(shè)置互斥鎖, 所以?xún)蓚€(gè)方法是同時(shí)對(duì)同一個(gè)變量進(jìn)行修改, 得到的的結(jié)果值是隨機(jī)的

下面我們改一下上面的代碼 , 兩個(gè)方法加上互斥鎖:

a = 0
lock = threading.Lock()	# 實(shí)例化互斥鎖對(duì)象, 方便之后的調(diào)用

def incr(n):
 global a
 for i in range(n):
 lock.acquire()	# 上鎖的方法
 a += 1
 lock.release()	# 解鎖的方法
# 要注意的是上鎖的位置是, 出現(xiàn)修改操作的代碼
def decr(n):
 global a
 for i in range(n):
 with lock:	# 也可以直接使用with, 自動(dòng)解鎖
  a -= 1

t_incr = threading.Thread(target=incr, args=(1000000,))
t_decr = threading.Thread(target=decr, args=(1000000,))
t_incr.start()
t_decr.start()
t_incr.join()
t_decr.join()
print(a)
# Result: 0

在容易出現(xiàn)搶奪資源的地方進(jìn)行上鎖 , 實(shí)現(xiàn)同一時(shí)間內(nèi) , 只有一個(gè)線(xiàn)程可以對(duì)對(duì)象進(jìn)行操作

隊(duì)列Queue

常用方法

關(guān)鍵字 解釋
put(item) 入隊(duì) , 將item放入隊(duì)列中 , 在隊(duì)列為滿(mǎn)時(shí)插入值會(huì)發(fā)生阻塞(1)
get() 出隊(duì) , 從隊(duì)列中移除并返回一個(gè)數(shù)據(jù) , 在隊(duì)列為空時(shí)獲取值會(huì)發(fā)生阻塞
task_done() 任務(wù)結(jié)束 , 意味著之前入隊(duì)的一個(gè)任務(wù)已經(jīng)完成。由隊(duì)列的消費(fèi)者線(xiàn)程調(diào)用
join() 等待完成 , 阻塞調(diào)用線(xiàn)程,直到隊(duì)列中的所有任務(wù)被處理掉。
empty() 如果隊(duì)列為空,返回True,反之返回False
full() 如果隊(duì)列為滿(mǎn),返回True,反之返回False
qsize() 隊(duì)列長(zhǎng)度 , 返回當(dāng)前隊(duì)列的數(shù)據(jù)量

(1): 阻塞: 程序停在阻塞的位置 , 無(wú)法繼續(xù)執(zhí)行

導(dǎo)入和實(shí)例化

import queue
q = queue.Queue(4)	# 實(shí)例化隊(duì)列對(duì)象, 并設(shè)置最大數(shù)據(jù)量

put() 和 get()

q.put('a')
q.put('b')
print(q.get()) # : a
print(q.get()) # : b
q.task_done() # get后必須要加task_done,確認(rèn)get操作是否完成
q.put(1)  # 當(dāng)前隊(duì)列已滿(mǎn),再次put就會(huì)阻塞
print(q.full()) # 由于已經(jīng)阻塞, 所以這段不會(huì)被執(zhí)行
# put會(huì)在隊(duì)列慢了點(diǎn)時(shí)候,在插入值會(huì)發(fā)生阻塞
# get會(huì)在隊(duì)列里沒(méi)有值的時(shí)候,會(huì)發(fā)生阻塞

empty()

print(q.empty()) # 判斷隊(duì)列是否為空: True
q.put('test')
print(q.empty()) # : False

qsize()

print(q.qsize()) # 當(dāng)前隊(duì)列里有多少人: 1

full()

q.put(1)
q.put(1)
q.put(1)
print(q.full()) # : True

join()

print('testetsetset')
q.join() # join會(huì)在隊(duì)列非空時(shí)發(fā)生阻塞
print('done') # 由于已經(jīng)阻塞, 所以這段不會(huì)被執(zhí)行

線(xiàn)程池

池的概念

線(xiàn)程池中實(shí)現(xiàn)準(zhǔn)備好了一些可以重復(fù)使用的線(xiàn)程 , 等待接受任務(wù)并執(zhí)行

主線(xiàn)程提交任務(wù)給 線(xiàn)程池 , 線(xiàn)程池中的每個(gè)線(xiàn)程會(huì)一次一個(gè)的接收任務(wù)并執(zhí)行 , 直到主線(xiàn)程執(zhí)行結(jié)束

主線(xiàn)程: 相當(dāng)于生產(chǎn)者,只管向線(xiàn)程池提交任務(wù)。
并不關(guān)心線(xiàn)程池是如何執(zhí)行任務(wù)的。
因此,并不關(guān)心是哪一個(gè)線(xiàn)程執(zhí)行的這個(gè)任務(wù)。

線(xiàn)程池: 相當(dāng)于消費(fèi)者,負(fù)責(zé)接收任務(wù),
并將任務(wù)分配到一個(gè)空閑的線(xiàn)程中去執(zhí)行。

自定義線(xiàn)程池

import queue
import threading
import time


class ThreadPool: # 自定義線(xiàn)程池

 def __init__(self, n): # 主線(xiàn)程做

 self.queue_obj = queue.Queue()
 for i in range(n):
  threading.Thread(target=self.worker, daemon=True).start() # 給子線(xiàn)程worker設(shè)置為守護(hù)模式

 def worker(self): # 子線(xiàn)程做,由于Debug調(diào)試的只是主線(xiàn)程的代碼,所以在調(diào)試時(shí)看不到子線(xiàn)程執(zhí)行的代碼
 """線(xiàn)程對(duì)象,寫(xiě)while True 是為了能夠一直執(zhí)行任務(wù)。"""
 while True: # 讓線(xiàn)程執(zhí)行完一個(gè)任務(wù)之后不會(huì)死掉,主線(xiàn)程結(jié)束時(shí),守護(hù)模式會(huì)讓worker里的死循環(huán)停止
  func = self.queue_obj.get() # get已經(jīng)入隊(duì)的任務(wù), 這里會(huì)接收到主線(xiàn)程分配的func
  # 由于設(shè)置了守護(hù)模式,當(dāng)隊(duì)列為空時(shí),不會(huì)一直阻塞在get這里
  # 有了守護(hù)模式,worker會(huì)在主線(xiàn)程執(zhí)行完畢后死掉
  func() # 將隊(duì)列里的任務(wù)拿出來(lái)調(diào)用
  """
  這里func與task_done的順序非常重要,如果func放在task_done后面的話(huà)會(huì)出現(xiàn)只執(zhí)行兩次就結(jié)束。
  """
  self.queue_obj.task_done() # task_done 會(huì)刷新計(jì)數(shù)器
  # 線(xiàn)程池里有一個(gè)類(lèi)似計(jì)數(shù)器的機(jī)制,用來(lái)記錄put的次數(shù)(+1),每一次task_done都會(huì)回?fù)芤淮斡涗浀拇螖?shù)(-1)
  # 當(dāng)回?fù)芡暧?jì)數(shù)器為0之后,就會(huì)執(zhí)行join

 def apply_async(self, func): # 主線(xiàn)程做
 """向隊(duì)列中傳入需要執(zhí)行的函數(shù)對(duì)象"""
 self.queue_obj.put(func) # 將接收到的func入隊(duì)

 def join(self): # 主線(xiàn)程做
 """等待隊(duì)列中的內(nèi)容被取完"""
 self.queue_obj.join() # 隊(duì)列里不為空就阻塞,為空就不阻塞

簡(jiǎn)單使用

def task1(): # 子線(xiàn)程做
 time.sleep(2)
 print('task1 over')

def task2(): # 子線(xiàn)程做
 time.sleep(3)
 print('task2 over')

P = ThreadPool(2) # 如果在start開(kāi)啟線(xiàn)程之后沒(méi)有傳入任務(wù)對(duì)象,worker里的get會(huì)直接阻塞
P.apply_async(task1)
P.apply_async(task2)

print('start')
P.join()
print('done')

# Result: 
start
task1 over
task2 over
done

如果get發(fā)生阻塞意味著隊(duì)列為空,意味著join不阻塞,意味著print('done')會(huì)執(zhí)行,
意味著主線(xiàn)程沒(méi)有任務(wù)在做,意味著主線(xiàn)程結(jié)束,意味著不等待設(shè)置了守護(hù)的線(xiàn)程執(zhí)行任務(wù),
意味著子線(xiàn)程會(huì)隨著主線(xiàn)程的死亡而死亡,這就是為什么會(huì)設(shè)置守護(hù)模式。

如果沒(méi)有設(shè)置守護(hù)模式意味著get發(fā)生阻塞,意味著子線(xiàn)程任務(wù)執(zhí)行不完,意味著主線(xiàn)程一直要等子線(xiàn)程完成,
意味著程序一直都結(jié)束不了,意味著程序有問(wèn)題

python內(nèi)置線(xiàn)程池

原理

  1. 創(chuàng)建線(xiàn)程池
  2. 將任務(wù)扔進(jìn)去
  3. 關(guān)閉線(xiàn)程池
  4. 等待線(xiàn)程任務(wù)執(zhí)行完畢

 '''手動(dòng)實(shí)現(xiàn)線(xiàn)程池:
主要是配合隊(duì)列來(lái)進(jìn)行實(shí)現(xiàn),我們定義好一個(gè)隊(duì)列對(duì)象,然后將我們的任務(wù)對(duì)象put到我們的隊(duì)列對(duì)象中,
然后使用多線(xiàn)程,讓我們的線(xiàn)程去get隊(duì)列種的對(duì)象,然后各自去執(zhí)行自己get到的任務(wù),
這樣的話(huà)其實(shí)也就實(shí)現(xiàn)了線(xiàn)程池
'''

使用方法

from multiprocessing.pool import ThreadPool
import time

pool = ThreadPool(2) # 直接使用內(nèi)置線(xiàn)程池, 設(shè)置最大線(xiàn)程數(shù)

def task1():
 time.sleep(2)
 print('task1 over')

def task2(*args, **kwargs):
 time.sleep(3)
 print('task2 over', args, kwargs)

pool.apply_async(task1)
pool.apply_async(task2, args=(1, 2), kwds={'a': 1, 'b': 2})
print('Task Submitted')
pool.close() # 要點(diǎn): close必須要在join之前, 不允許再提交任務(wù)了
pool.join()
print('Mission Complete')

# Result:
Task Submitted
task1 over
task2 over (1, 2) {'a': 1, 'b': 2}
Mission Complete

其他操作

操作一: close - 關(guān)閉提交通道,不允許再提交任務(wù)

操作二: terminate - 中止進(jìn)程池,中止所有任務(wù)

以上所述是小編給大家介紹的python線(xiàn)程與線(xiàn)程池詳解整合,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

最新評(píng)論

普兰县| 青神县| 宽甸| 吴堡县| 吴江市| 嘉祥县| 高碑店市| 通城县| 会同县| 宜黄县| 闸北区| 霸州市| 涞源县| 贡嘎县| 穆棱市| 台南市| 县级市| 蓝田县| 银川市| 溆浦县| 泗阳县| 航空| 康定县| 绵竹市| 亚东县| 邵武市| 隆化县| 五家渠市| 平江县| 清苑县| 鄂州市| 连城县| 惠水县| 宜兰市| 上高县| 武安市| 田林县| 福清市| 威信县| 微山县| 万山特区|