--coding:utf-8--
2 python實現線程的方式
1.函數方式(涉及_thread模塊)
2.用類包裝線程對象(涉及threading模塊)
2.1函數方式實現多線程
1.調用_thread模塊的start_new_thread()函數創(chuàng)建并啟動新線程
語法:_thread.start_new_thread(function,args[,kwargs])
function:線程函數
args:傳遞給線程函數的參數,必須是tuple類型
kwargs:可選參數
import _thread
import time
def workThread(threadName,delay):
print('[啟動]>>>{0}'.format(threadName))
counter = 0 #計數器
for i in range(delay):
counter += 1
time.sleep(1)
pass
print('[停止]>>>{0}'.format(threadName))
pass
if __name__ == '__main__':
_thread.start_new_thread(workThread,('thread-1',3))
_thread.start_new_thread(workThread,('thread-2',5))
for i in range(4):
print('mainThread正在執(zhí)行')
time.sleep(1)
pass
print('>>>主線程mainThread停止\a')
print('-' * 50)
備注:線程結束一般依靠線程函數的自然結束蹬叭,也可在線程中調用thread.exit(),拋出SystemExit exception 達到退出線程的目的
2.2模塊實現方式
python通過兩個標準庫_thread和threading提供線程支持
_thread提供低級別的枕磁,原始的線程以及一個簡單的鎖
threading模塊提供其他方法:
1.threading.currentThread():返回當前線程變量
2.threading.enumerate():返回一個包含正在運行線程的list秦叛,正在運行線程啟動后脑蠕,結束前艺谆,不包括啟動前和終止后的線程
3.threading.activeCount():返回正在運行的線程數量棵红,與len(threading.enumerate())有相同的結果
除此之外胀糜,線程模塊提供threading.Thread類來處理線程祟昭,threading.Thread提供如下函數
1.run():表示線程活動的方法
2.start():啟動線程活動
3.join([time]):等待至線程中止缕坎,這阻塞調用線程直至線程的join()方法被調用中止-正常退出或者拋出未處理的異常-或者是可選
4.isAlive():返回線程是否是活動的
5.getName():返回線程名
6.setName():設置線程名
語法:
import threading
#創(chuàng)建線程類
class 線程類名稱(threading.Thread):
def __init__(self,參數1,...,參數N):
#調用父類構造方法
threading.thread.__init__(self)
...
#重寫run(),線程啟動后的調用
def run():
...
線程對象 = 線程類名稱()
線程對象.run() #啟動線程
import threading
import time
exitFlag = 0 #創(chuàng)建推出標志位變量
def outputTime(threadName,delay,counter):
while counter:
if exitFlag:
threading.Thread.exit()
time.sleep(delay)
print('%s:%s' % (threadName,time.ctime(time.time())))
counter -= 1
pass
pass
class MyThread(threading.Thread):
"""docstring for MyThread"""
def __init__(self, threadID,name,counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print('啟動>' + self.name)
outputTime(self.name,self.counter,5)
print('結束>' + self.name)
pass
if __name__ == '__main__':
print('mainThread主線程啟動.....')
thread1 = MyThread(1,'thread-11',1)
thread2 = MyThread(2,'thread-22',1)
thread1.run()
thread2.run()
print('mainThread主線程結束')
3.線程同步
線程有五個狀態(tài),狀態(tài)切換如下
啟動 調度 結束
新建 就緒 運行 死亡
| 阻塞條件
阻塞
所線程在執(zhí)行時為隨機模式篡悟,不可控谜叹,要求執(zhí)行順序可控就得用線程同步
Python 線程同步技術的解決方案:鎖同步和條件變量同步
3.1創(chuàng)建線程鎖的語法:
線程鎖對象 = Threading.Lock
鎖定:線程鎖對象.acquire()
解除鎖定:線程鎖對象.release()
使用場景:
def run(self):
線程鎖對象.acquire()
...線程執(zhí)行語句...
線程鎖對象.release()
#3.2條件變量同步
python 提供的Condition對象提供了對復雜線程同步問題的支持
Condition被稱為條件變量,除了提供Lock類似的acquire和release方法搬葬,還提供wait和notify
工作原理:
線程首先acquire一個條件變量荷腊,然后判斷一些條件,不滿足wait,滿足進行處理改變條件后急凰,通過notify方法通知其他線程女仰,其他處于wait的線程接到通知會重新判斷條件,重復這一過程抡锈,從而解決復雜的同步問題
示例:生產者和消費者
生產者消費者問題(有限緩沖問題)疾忍,是一個多線程同步的經典案例,該問題描述兩個共享固定大小緩存的線程--即所謂的‘生產者‘和’消費者‘在實際運行時會發(fā)生的問題
生產者作用時生成一定量的數據放到緩沖區(qū)企孩,重復此過程
消費者在緩沖區(qū)消耗這些數據
該問題的【關鍵】保證生產者不會在緩沖區(qū)滿時加入數據锭碳,消費者也不會在緩沖區(qū)空時消耗數據
任務說明:
1.創(chuàng)建一個共享區(qū),容量是10
2.兩個生產者勿璃,隨機時間單位產生1件商品放入共享區(qū)擒抛,count + 1,共享區(qū)滿补疑,生產者停止放入共享區(qū)歧沪,線程進入block阻塞狀態(tài),等待消費者線程喚醒
3.五個消費者莲组,隨機時間單位產生從共享區(qū)取1件商品诊胞,count - 1,共享區(qū)空,消費者停止從共享區(qū)獲取撵孤,線程進入block阻塞狀態(tài)迈着,等待生產者線程喚醒
import threading
import time
import random #隨機模塊
#使用共享區(qū)模擬變量
count= 0
#創(chuàng)建條件對象
condition = threading.Condition()
#生產者線程類
class Producer(threading.Thread):
def __init__(self,threadName):
threading.Thread.__init__(self)
self.threadName = threadName
def run(self):
global count #引用全局共享變量count
while True:
#使用條件變量后去鎖并速定
if condition.acquire():
#判斷共享變量是否達到上限(已滿)
if count >= 10:
print('共享區(qū)已滿,生產者Producer線程進入阻塞block狀態(tài)邪码,停止放入裕菠!')
#當前線程進入阻塞狀態(tài)
condition.wait()
else:
count += 1 #共享變量自增1
print(time.ctime() + ' ' + self.threadName + '生產了1件商品放入共享區(qū),共享區(qū)商品總計個數:{0}'.format(count))
condition.notify() #喚醒其他阻塞線程
condition.release()
time.sleep(random.randrange(10)/5) #隨機休眠N秒
#消費者線程
class Customer(threading.Thread):
def __init__(self, threadName):
threading.Thread.__init__(self)
self.threadName = threadName
def run(self):
global count #引用全局共享變量count
while True:
#使用條件變量后去鎖并速定
if condition.acquire():
#判斷共享變量是否達到上限(已滿)
if count < 1:
print('共享區(qū)已空闭专,消費者Customer線程進入阻塞block狀態(tài)奴潘,停止獲取影钉!')
#當前線程進入阻塞狀態(tài)
condition.wait()
else:
count -= 1 #共享變量自減1
print(time.ctime() + ' ' + self.threadName + '消費了1件商品画髓,共享區(qū)商品總計個數:' + str(count))
condition.notify() #喚醒其他阻塞線程
condition.release()
time.sleep(random.randrange(10)) #隨機休眠N秒
if __name__ == '__main__':
for i in range(2):
p = Producer('[生產者-' + str(i + 1) + ']')
p.start()
for i in range(5):
c = Producer('[消費者-' + str(i + 1) + ']')
c.start()