您好,登錄后才能下訂單哦!
同時做某些事,可以互不干擾的同一時刻做幾件事
如高速公路上的車道,同一時刻,可以有多個互不干擾的車運行
在同一時刻,每條車道上可能同時有車輛在跑,是同時發生的概念
也是同時做某事,但強調的是同一時段做了幾件事。
并行是可以解決并發問題的。
隊列:排隊就是隊列,先進先出,解決了資源使用的問題。
緩沖區:排程的隊列,其實就是一個緩沖地帶,就是緩沖區
優先隊列:對比較重要的事進行及時的處理,此處就是優先隊列
只開一個窗口,有可能沒秩序,也就是誰擠進去就給誰打飯
擠到窗口的人占據窗口,直到達到飯菜離開,其他人繼續爭搶,會有一個人占據窗口,可以視為鎖定窗口,窗口就不能為其他人提供服務了,這是一種鎖機制,搶到資源就上鎖,排他性鎖,其他人只能等候爭搶也是一種高并發解決方案,但是,不好,因為有人可能長時間搶不到。
一種提前加載用戶需要的數據的思路,如預熱,預加載等,緩存中常用
緩存的思想就是將數據直接拿到,進行處理。
可通過購買更多的服務器,或開多線程,進行實現并行處理,來解決并發問題,這些都是水平擴展,
提高單個CPU性能,或者單個服務器安裝更多的CPU,但此和多個服務器相比成本較高
通過中間的緩沖器來解決并發問題,如rabbitmq,activemq,rocketmq,kafka 等,CDN也算是一種
在實現了線程的操作系統中,線程是操作系統能夠運算調度的最小單位,他被包含在進程中,是進程中的實際運作單位,一個程序的執行實例就是一個進程
進程(process)是計算機中的程序關于某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位,是操作系統結構的基礎
程序是源代碼編譯后的文件,而這些文件存放在磁盤上,當程序被操作系統加載到內存中,就是進程,進程中存放著指令和數據(資源),它也是線程的容器。
Linux進程有父進程,子進程,windows中進程之間是平等關系
線程有時候被稱為輕量級進程(LWP),是程序執行的最小單元,一個標準的線程由線程ID,當前指令指針(PC),寄存器集合和堆棧組成
現代操作系統提出進程的概念,每一個進程都認為自己獨占所有計算機硬件資源,進程就是獨立王國,進程間不能隨便共享數據
線程就是省份,同一個進程內的線程可以共享進程的資源,每一個線程擁有自己獨立的堆棧。
進程會啟動一個解釋器進程,線程共享一個解釋器進程
兩個解釋器進程之間是沒有任何關系的,不同進程之間是不能隨便交互數據的
大多數數據都是跑在主線程上的
1 運行態: 該時刻,該線程正在占用CPU資源
2 就緒態:可隨時轉換成運行態,因為其他線程正在運行而暫停,該線程不占CPU
3 阻塞態: 除非外部某些事情發生,否則線程不能運行
4 終止: 線程完成,或退出,或被取消
先創建進程,然后再創建一個線程
等待資源的運行
阻塞不能直接進入運行狀態,必須先進入就緒狀態
運行中的線程是可以被取消的
簽名
def __init__(self, group=None, target=None, name=None,
args=(), kwargs=None, *, daemon=None):
參數名及含義:
target:線程調用的對象,就是目標函數
name:為線程起名字(不同線程的名字可以重復,主要是通過線程TID進行區分的)
args:為目標函數傳遞參數,元祖
kwargs: 為目標函數關鍵字傳參,字典
實例如下
#!/usr/bin/poython3.6
#conding:utf-8
import threading
def test():
for i in range(5):
print (i)
print ('Thread over')
# 實例化一個線程
t=threading.Thread(target=test)
t.start() # 啟動一個線程
隨著函數的執行完成,線程也就結束了,子線程不結束,則主線程一直存在,此時的主線程是等待狀態
通過threading.Thread創建一個線程對象,target是目標函數,name可以指定名稱,但是線程沒有啟動,需要調用start方法。
線程之所以能執行函數,是因為線程中就是執行代碼,而最簡單的封裝就是哈函數,所以還是函數調用。
函數執行完成,線程就退出了,如果不讓線程退出,則需要使用死循環
#!/usr/bin/poython3.6
#conding:utf-8
import threading
def test():
for i in range(5):
print (i)
print ('Thread over')
# 實例化一個線程
t=threading.Thread(target=test,name='test1')
t.start() # 啟動一個線程
t=threading.Thread(target=test,name='test2')
t.start() # 啟動一個線程
# 上述兩個線程是并行處理,如果是一個CPU,則是假的平衡
結果如下
python中沒有提供線程退出的方式,線程在下面情況時退出、
1 線程函數內語句執行完畢
2 線程函數中拋出未處理的異常
#!/usr/bin/poython3.6
#conding:utf-8
import threading
def test():
count=0
while True:
count+=1
if count==3:
raise Exception('NUMBER')
print (count)
# 實例化一個線程
t=threading.Thread(target=test,name='test1')
t.start() # 啟動一個線程
異常導致的線程退出
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
def test():
count=0
while True:
count+=1
if count==3:
raise Exception('NUMBER')
print (count)
def test1():
for i in range(5):
time.sleep(0.1)
print ('test1',i)
# 實例化一個線程
t=threading.Thread(target=test,name='test')
t.start() # 啟動一個線程
t=threading.Thread(target=test1,name='test1') #此處啟用一個線程,看上述線程能否影響該線程的運行情況
t.start()
結果如下
python中線程沒有優先級,沒有線程組的概念,也不能被銷毀,停止,掛起,也就沒有恢復,中斷了,上述的一個線程的異常不能影響另一個線程的運行,另一個線程的運行是因為其函數運行完成了
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
def test(count):
while True:
count+=1
if count==5:
raise Exception('NUMBER')
print (count)
# 實例化一個線程
t=threading.Thread(target=test,name='test',args=(0,)) #此處必須是元祖類型,否則會報錯
t.start() # 啟動一個線程
current_thread() 返回當前線程對象
main_thread() 返回主線程對象
active_count() 當前處于alive狀態的線程個數
enumerate() 返回所有活著的線程的列表,不包括已經終止的線程和未開始的線程
get_ident() 返回當前線程的ID,非0整數
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
def test(count):
while True:
print ("當前線程對象為{}當前處于活動的線程個數為{}".format(threading.current_thread(),threading.active_count()))
count+=1
if count==5:
break
print (count)
print('當前活著的線程列表為:', threading.enumerate())
# 實例化一個線程
t=threading.Thread(target=test,name='test',args=(0,)) #此處必須是元祖類型,否則會報錯
t.start() # 啟動一個線程
print ('當前活著的線程列表為:',threading.enumerate())
print ('當前處于活動的線程個數為{} ,當前主線程為{},當前線程ID為{}'.format(threading.active_count(),threading.main_thread(),threading.get_ident()))
結果如下
其線程的執行不是順序的,其調用取決于CPU的調度規則,而主線程在子線程所有子線程退出之前都是active狀態。
name : 線程的名字,只是一個標識,其可以重名,getname() 獲取,setname()設置這個名詞
ident:線程ID,其是非0整數,線程啟動后才會有ID,否則為None,線程退出,此ID依舊可以訪問,此ID可以重復使用
is_alive() 返回線程是否活著
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
def test(count):
while True:
count+=1
if count==5:
break
print (count)
print ('當前線程name 為{},ID 為{}'.format(threading.current_thread().name,threading.current_thread().ident))
# 實例化一個線程
t=threading.Thread(target=test,name='test',args=(0,)) #此處必須是元祖類型,否則會報錯
t.start() # 啟動一個線程
print ('主線程狀態',threading.main_thread().is_alive())
print ('線程狀態',threading.current_thread().is_alive())
結果如下
start() 啟動線程,每一個線程必須且只能被執行一次
run() 運行線程函數
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
class MyThread(threading.Thread): # 自定義一個類,其繼承Thread的相關start和run屬性
def start(self) -> None:
print ('start',self)
super().start()
def run(self) -> None:
print ('run',self)
super().run()
def work():
print ('本線程ID為{},主線程ID為{}'.format(threading.current_thread().ident,threading.main_thread().ident))
print ('test')
t=MyThread(target=work,name='w')
t.start()
結果如下
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
class MyThread(threading.Thread): # 自定義一個類,其繼承Thread的相關start和run屬性
def start(self) -> None:
print ('start',self)
super().start()
def run(self) -> None:
print ('run',self)
super().run()
def work():
print ('本線程ID為{},主線程ID為{}'.format(threading.current_thread().ident,threading.main_thread().ident))
print ('test')
t=MyThread(target=work,name='w')
t.run()
結果如下
結論如下:start 方法的調用會產生新的線程,而run的調用是在主線程中運行的,且run的調用只會調用自己的方法,而start 會調用自己和run方法
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
class MyThread(threading.Thread): # 自定義一個類,其繼承Thread的相關start和run屬性
def start(self) -> None:
print ('start',self)
super().start()
def run(self) -> None:
print ('run',self)
super().run()
def work():
print ('test')
t=MyThread(target=work,name='w')
t.start()
time.sleep(3)
t.start() #再次啟用線程
上述可知,線程在start是會調用start和run屬性運行,且其不能再次啟動線程一次。
調用run方法
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
class MyThread(threading.Thread): # 自定義一個類,其繼承Thread的相關start和run屬性
def start(self) -> None:
print ('start',self)
super().start()
def run(self) -> None:
print ('run',self)
super().run()
def work():
print ('test')
t=MyThread(target=work,name='w')
t.run()
time.sleep(3)
t.run()
結果如下
run 方法也只能調用一次
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
class MyThread(threading.Thread): # 自定義一個類,其繼承Thread的相關start和run屬性
def start(self) -> None:
print ('start',self)
super().start()
def run(self) -> None:
print ('run',self)
super().run()
def work():
print ('test')
t=MyThread(target=work,name='w')
t.run()
time.sleep(3)
t.start()
結果如下
上述結果表明,run和start的調用不能出現在同一個線程中
重新構建一個新線程并啟動
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
class MyThread(threading.Thread): # 自定義一個類,其繼承Thread的相關start和run屬性
def start(self) -> None:
print ('start',self)
super().start()
def run(self) -> None:
print ('run',self)
super().run()
def work():
print ('test')
t=MyThread(target=work,name='w')
t.start()
t=MyThread(target=work,name='w1')
t.start()
結果如下
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
class MyThread(threading.Thread): # 自定義一個類,其繼承Thread的相關start和run屬性
def start(self) -> None:
print ('start',self)
super().start()
def run(self) -> None:
print ('run',self)
super().run()
def work():
print ('test')
t=MyThread(target=work,name='w')
t.run()
t=MyThread(target=work,name='w1')
t.run()
結果如下
注釋繼承的run方法
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
class MyThread(threading.Thread): # 自定義一個類,其繼承Thread的相關start和run屬性
def start(self) -> None:
print ('start',self)
super().start()
def run(self) -> None:
print ('run',self)
# super().run()
def work():
print ('test')
t=MyThread(target=work,name='w')
t.start()
t=MyThread(target=work,name='w1')
t.start()
結果如下
禁用start方法
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
class MyThread(threading.Thread): # 自定義一個類,其繼承Thread的相關start和run屬性
def start(self) -> None:
print ('start',self)
#super().start()
def run(self) -> None:
print ('run',self)
super().run()
def work():
print ('test')
t=MyThread(target=work,name='w')
t.start()
t=MyThread(target=work,name='w1')
t.start()
結論:start()函數會調用run函數,而run()函數是用來運行函數的,start是創建線程的,在執行start()時run()必不可少,而在運行run()時因為不需要調用start(),因此其是非必須的。
start 會啟用新的線程,其使用可以形成多線程,而run()是在當前線程中調用函數,不會產生新的線程,其均不能多次調用
一個進程中如果有多個線程,就是多線程,實現一種并發
線程的調度任務是操作系統完成的
沒有開新的線程,這就是普通的函數調用,所以執行完t1.run(),然后執行t2.run(),這不是多線程
當使用start方法啟動線程時,進程內有多個活動的線程并行工作,就是多線程
一個進程中至少有一個線程,作為程序的入口,這個線程就是主線程,一個進程至少有一個主線程
其他線程稱為工作線程
python中的線程沒有優先級的概念
此實例需要在ipython 中運行
此處的print 會被打斷,其中間有空格,此種情況稱為線程不安全。
print 函數的執行分為兩步:
1 打印字符串
2 換行,就在這之間發生了線程切換,其不安全
1 通過字符串的拼接來完成
2 通過logging模塊來處理,其輸出過程中是不被打斷的
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import logging # 導入日志打印模塊
logging.basicConfig(level=logging.INFO) #定義基本級別,默認是WARNING,此處修改為INFO
def woker():
for x in range(10):
msg="{} is running".format(threading.current_thread())
logging.info(msg) # 日志打印
for x in range(5):
t = threading.Thread(target=woker,name="work-{}".format(x)).start()
結果如下
簡單測試的時候使用print,在其他應用的時候必須使用logging,其是針對日志打印使用的技術,日志打印過程中是不能被中斷的,
這里的daemon線程不是Linux中的守護進程
進程靠線程執行代碼,至少一個主線程,其他線程是工作線程
主線程是第一個啟動的線程
父線程: 如果線程A中啟動了一個線程B,A就是B的父線程
子線程: B就是A的子線程在python中,構建線程的時候,可以設置daemon屬性,這個屬性必須在start方法之前設置好,
相關源碼
此處表明。若傳入的daemon 不是None,則其表示默認傳入的值,否則,及若不傳入,則表示使用當前線程的daemon
主線程是non-daemon線程,及daemon=False
活著線程的列表的源碼
此處表示活著的線程列表中一定會包含主線程,
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import logging # 導入日志打印模塊
logging.basicConfig(level=logging.INFO) #定義基本級別,默認是WARNING,此處修改為INFO
def woker():
for x in range(10):
msg="{} is running".format(threading.current_thread())
logging.info(msg) # 日志打印
threading.Thread(target=woker,name="work-{}".format(0)).start()
print ('ending')
print (threading.enumerate()) #主線程因為其他線程的執行,因此其處于等待狀態
結果如下
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import logging # 導入日志打印模塊
logging.basicConfig(level=logging.INFO) #定義基本級別,默認是WARNING,此處修改為INFO
def woker():
for x in range(10):
msg="{} is running".format(threading.current_thread())
logging.info(msg) # 日志打印
threading.Thread(target=woker,name="work-{}".format(0),daemon=True).start() #主線程一般會在一定時間內掃描屬性列表,若其中有non-daemon類型
# 的線程,則會等待其執行完成再退出,若是遇見都是daemon類型線程,則直接退出,
print ('ending')
print (threading.enumerate()) #主線程因為其他線程的執行,因此其處于等待狀態
結果如下
上述線程是daemon線程,因此主線程不會等待其完成后再關閉
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import logging # 導入日志打印模塊
import time
logging.basicConfig(level=logging.INFO) #定義基本級別,默認是WARNING,此處修改為INFO
def woker():
for x in range(10):
msg="{} {} is running".format(x,threading.current_thread())
logging.info(msg) # 日志打印
time.sleep(0.5) #此處配置延遲,檢驗是否在non-daemon線程執行完成后及會直接關閉的情況
threading.Thread(target=woker,name="work-{}".format(0),daemon=True).start() #主線程一般會在一定時間內掃描屬性列表,若其中有non-daemon類型
# 的線程,則會等待其執行完成再退出,若是遇見都是daemon類型線程,則直接退出,、
def woker1():
for x in ['a','b','c','d']:
msg="{} {} is running".format(x,threading.current_thread())
logging.info(msg) # 日志打印
threading.Thread(target=woker1,name="work-{}".format(0)).start() #主線程一般會在一定時間內掃描屬性列表,若其中有non-daemon類型,則不會終止,
# 此處默認從父線程中獲取屬性,父線程中是non-daemon,因此此屬性會一直運行,上面的會關閉,但不會影響這個
print ('ending')
print (threading.enumerate()) #主線程因為其他線程的執行,因此其處于等待狀態
結果如下
結果表示,當non-daemon線程執行完成后,不管damon是否執行完成,主線程將直接終止,不會再次運行。
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import logging # 導入日志打印模塊
import time
def woker1():
for x in ['a','b','c','d']:
msg="{} {} is running".format(x,threading.current_thread())
logging.info(msg) # 日志打印
logging.basicConfig(level=logging.INFO) #定義基本級別,默認是WARNING,此處修改為INFO
def woker():
for x in range(10):
msg="{} {} is running".format(x,threading.current_thread())
logging.info(msg) # 日志打印
time.sleep(1) # 此處配置1秒延時,使得主線程看不到孫子線程的non-daemon就關閉
T3=threading.Thread(target=woker1,name="woker{}".format(10),daemon=False) #此處啟動的線程默認是non-daemon線程,但由于其父線程是daemon
# 及就是下面的T1線程,當T2線程執行完畢后線程掃描,發現沒non-daemon線程,則直接退出,此時將不會繼續執行T1 的子線程T3,雖然T3是non-daemon。因為其未啟動
T3.start()
T1=threading.Thread(target=woker,name="work-{}".format(0),daemon=True)#主線程一般會在一定時間內掃描屬性列表,若其中有non-daemon類型
T1.start()
# 的線程,則會等待其執行完成再退出,若是遇見都是daemon類型線程,則直接退出,
T2=threading.Thread(target=woker1,name="work-{}".format(0)) #主線程一般會在一定時間內掃描屬性列表,若其中有non-daemon類型,則不會終止,
# 此處默認從父線程中獲取屬性,父線程中是non-daemon,因此此屬性會一直運行,上面的會關閉,但不會影響這個
T2.start()
print ('ending')
print (threading.enumerate()) #主線程因為其他線程的執行,因此其處于等待狀態
結果如下
可能孫子線程還沒起來,主線程只看到了daemon線程。則直接進行關閉,
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import logging # 導入日志打印模塊
import time
def woker1():
for x in ['a','b','c','d']:
msg="{} {} is running".format(x,threading.current_thread())
logging.info(msg) # 日志打印
logging.basicConfig(level=logging.INFO) #定義基本級別,默認是WARNING,此處修改為INFO
def woker():
for x in range(10):
msg="{} {} is running".format(x,threading.current_thread())
logging.info(msg) # 日志打印
# time.sleep(1) # 此處配置1秒延時,使得主線程看不到孫子線程的non-daemon就關閉
T3=threading.Thread(target=woker1,name="woker{}".format(10),daemon=False) #此處啟動的線程默認是non-daemon線程,但由于其父線程是daemon
# 及就是下面的T1線程,當T2線程執行完畢后線程掃描,發現沒non-daemon線程,則直接退出,此時將不會繼續執行T1 的子線程T3,雖然T3是non-daemon。因為其未啟動
T3.start()
T1=threading.Thread(target=woker,name="work-{}".format(0),daemon=True)#主線程一般會在一定時間內掃描屬性列表,若其中有non-daemon類型
T1.start()
# 的線程,則會等待其執行完成再退出,若是遇見都是daemon類型線程,則直接退出,
結果如下
也可能是孫子線程已經起來了,主線程看到了non-daemon線程,因此未直接關閉,而是等待孫子線程執行完成后才進行關閉操作
相關屬性
daemon 屬性 表示線程是否是daemon線程,這個值必須在start()之前設置,否則會引發異常
isDaemon() 是否是daemon線程
setDaemon() 設置為daemon線程,必須在start方法之前設置
總結:
python中父線程和子線程沒有直接的管理關系
python主線程是否殺掉線程,看的是daemon,若只有daemon,則直接刪掉所有線程,自己結束,若還有子線程是non-daemon,則會等待
如果想讓一個線程完整執行,則需要定義non-daemon屬性
daemon 屬性,必須在start 之前設置,否則會引發runtimeError異常
線程具有daemon屬性,可以顯示設置為True或False,也可以不設置,則去默認值None
如果不設置daemon,就區當前線程的daemon來設置它主線程是non-daemon線程,及daemon=False
從主線程創建的所有線程不設置daemon屬性,則默認都是daemon=False,也就是non-daemon線程
python程序在沒有活著的non-daemon線程運行時推出,也就是剩下的只有daemon線程,主線程才能退出,否則主線程就只能等待。
應用場景:
不關心什么時候開始,什么時候結束的時候使用daemon,否則可以使用non-daemonLinux的daemon是進程級別的,而python的daemon是線程級別的,其之間沒有可比性的
daemon和non-daemon 啟動的時候,需要注意啟動的時機。
簡單來說,本來并沒有daemon thread,為了簡化程序員工作,讓他們不去記錄和管理那些后臺線程,創造了daemon thread 的概念,這個概念唯一的作用就是,當你把一個線程設置為daemon時,它會隨著主線程的退出而退出。
主要應用場景:
1 后臺任務,發送心跳包,監控,這種場景較多。
2 主線程工作才有用的線程,如主線程中維護了公共資源,主線程已經清理了,準備退出,而工作線程使用這些資源工作也沒意義了,一起退出最合適
3 隨時可以被終止的線程
join是標準的線程函數之一,其含義是等待,誰調用join,誰等待
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import logging # 導入日志打印模塊
import time
def foo(n):
for i in range(n):
print (i)
time.sleep(0.5)
t1=threading.Thread(target=foo,args=(10,),daemon=True)
t1.start() # 默認情況下,此線程只能執行少量此,一般不能全部執行
t1.join() # 通過join方法將原本不能執行完成的線程執行完成了
結果如下
使用join方法,daemon線程執行完成后,主線程才退出,
join(timeout=None),是線程的標準方法之一。
timeout參數指定調用者等待多久,沒有設置超時,則就一直等到被調用線程結束,調用誰的join方法,就是join誰,誰就要等待。一個線程中調用另一個線程的join方法,調用者將被阻塞,直到被調用者線程終止,一個線程可以被join多次
如果在一個daemon C 線程中,對另一個daemon線程D 使用了join方法,只能說明C要等待D,主線程退出,C和D是否結束,也不管他們誰等待誰,都要被殺掉。
join 方法,支持使用等待,但其會導致多線程變成單線程,其會影響正常的運行,因此一般會將生成的線程加入到列表中,進行遍歷得到對應線程進行計算。
python 提供了threading.local 類,將這個實例化得到一個全局對象,但是不同的線程,這個對象存儲的數據其他線程看不到
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
def worker():
x=0 # 此處是局部變量
for i in range(10):
time.sleep(0.0001)
x+=1
print (threading.current_thread(),x)
for i in range(10):
threading.Thread(target=worker).start()
結果如下
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
x = 0 # 此處是一個全局變量
def worker():
for i in range(10):
global x
time.sleep(0.0001)
x+=1
print (threading.current_thread(),x)
for i in range(10):
threading.Thread(target=worker).start()
結果如下
局部變量本身具有隔離效果,一旦變成全局變量,則所有的線程都將能夠訪問和修改。
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
class A:
def __init__(self,x):
self.x=x
a=A(0)
def worker():
for i in range(100):
a.x=0
time.sleep(0.0001)
a.x+=1
print (threading.current_thread(),a.x)
for i in range(10):
threading.Thread(target=worker).start()
結果如下
其不同線程的TID是不同的,可通過不同線程的TID進行為鍵,其結果為值,便可解決此種亂象
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
a=threading.local() # 做到隔離,通過TID進行數據的隔離處理不同線程的不同數值問題
def worker():
a.x = 0
for i in range(100):
time.sleep(0.0001)
a.x+=1
print (threading.current_thread(),a.x)
for i in range(10):
threading.Thread(target=worker).start()
結果如下
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
a=threading.local() # 做到隔離,通過TID進行數據的隔離處理不同線程的不同數值問題
def worker():
a.x = 0
for i in range(100):
time.sleep(0.0001)
a.x+=1
print (threading.current_thread(),a.x)
print (threading.get_ident(),a.__dict__) #此處打印線程TID和字典
for i in range(10):
threading.Thread(target=worker).start()
結果如下
self.key 是 前面的加上id
通過字典實現,線程ID的地址是唯一的,但跨進程的線程ID 不一定是相同的進程中的線程地址可能是一樣的。每一個進程都認為自己是獨占資源的,但不一定就是 。
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
X='abc'
ctx=threading.local()
ctx.x=123
def work():
print (X)
print (ctx)
print (ctx.x) #此時的字典中ctx此ctx.x屬性,因此其不能打印,其是在線程內部,每個dict對應的值都是獨立的
print ('end')
threading.Thread(target=work).run() # 此處是本地線程調用,則不會影響
threading.Thread(target=work).start()
結果如下
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import time
X='abc'
ctx=threading.local()
ctx.x=123
def work():
print (X)
print (ctx)
ctx.x=100 #內部線程中定義一個局部變量,則可以執行和被調用
print (ctx.x) #此時的ctx 無此屬性,因此其不能打印,其是在線程內部,
print ('end')
threading.Thread(target=work).run() # 此處是本地線程調用,則不會影響
threading.Thread(target=work).start()
結果如下
threading.local類構件了一個大字典,其元素的每一線程實例的地址為Key和線程的引用線程單獨的字典的映射(棧),通過threading.local 實例就可以在不同的線程中,安全的使用線程獨有的數據,做到了線程間數據的隔離,如同本地變量一樣
上述可看到,其第一個字段便是時間
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import datetime
start_time=datetime.datetime.now()
def add(x,y):
print (x+y)
print("函數執行時間為{}".format((datetime.datetime.now() - start_time).total_seconds()))
t=threading.Timer(3,add,args=(3,4))
t.start() #此處會延遲3秒執行
結果如下
此處是延遲執行線程,而不是延遲執行函數,本質上還是線程
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import datetime
import time
def add(x,y):
print (x+y)
t=threading.Timer(6,add,args=(3,4)) # 此處表示6秒后出結果
t.start()
time.sleep(5)
t.cancel() #線程被刪除
只要是沒真正執行的線程,都能夠被cancel刪除
#!/usr/bin/poython3.6
#conding:utf-8
import threading
import datetime
import time
def add(x,y):
time.sleep(5)
print (x+y)
t=threading.Timer(6,add,args=(3,4)) # 此處表示6秒后出結果
t.start()
time.sleep(10)
t.cancel()
結果如下
start方法后,timer對象會處于等待狀態,等待interval之后,開始執行function函數,如果在執行函數之前等待階段,使用了cancel方法,就會跳過執行函數結束。
如果線程已經開始執行了,則cancel就沒有任何效果了
Timer是線程Thread的子類,就是線程類,具有線程的能力和特征
它的實例是能夠延遲執行目標函數的線程,在真正的執行目標函數之前,都可以cancel它 。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。