中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

38線程1-Thread-local-Timer

發布時間:2020-06-19 22:36:52 來源:網絡 閱讀:419 作者:chaijowin 欄目:編程語言

?

目錄

并發和并行:... 1

parallel,并行:... 1

concurrency,并發:... 2

并發的解決:... 2

1、隊列、緩沖區:... 2

2、爭搶:... 3

3、預處理:... 3

4、并行:... 3

5、提速:... 3

6、消息中間件:... 3

進程和線程:... 4

線程的狀態:... 5

py的線程開發:... 5

threading.Thread類:... 6

線程啟動:... 6

線程退出:... 7

線程的傳參:... 8

threading的屬性和方法:... 8

Thread實例的屬性和方法:... 9

t.start()t.run()... 9

線程安全:... 11

daemonnon-daemon... 11

t.join() 14

threading.local類:... 15

threading.Timer類:... 18

?

?

?

并發和并行:

parallel,并行:

同時做某些事,可互不干擾的同一時刻做幾件事;

?

例:

高速公路的車道,所有車輛(數據)可互不干擾的在自己的車道上奔跑(傳輸);在同一時刻,每條車道上可能同時有車輛在跑,是同時發生的概念;

?

在一定程度上,并行可解決并發問題;并行并不是解決并發的最佳方案;

?

?

concurrency,并發:

也是同時做某些事,但是強調,同一時段做了幾件事;

?

例:

鄉村公路一條車道,半幅路面出現了坑,交警指揮車輛走另外半幅路面,一個方向放行3min,換另一個方向,發生了車輛同時要通過路面的事件,這就是并發;

?

并發是在一時間點有很多事要做,并發太大,如何做?怎么做并不知道;

?

隊列、緩沖區:

鄉村公路窄,車輛就會排隊,所以排隊是一種天然解決并發的辦法,車輛排隊的緩沖地帶就是緩沖區;

?

并行:

鄉村公路窄,拓寬成雙向四車道,可同時雙向車道通行,通行車輛增多,能滿足一定的通行需求;

?

?

并發的解決:

食堂打飯模型:

中午12點,開飯,都涌向食堂,這就是并發,如果人很多,就是高并發;

?

1、隊列、緩沖區:

假設只有一個窗口,陸續涌入食堂的,排隊打菜是比較好的方式;

排隊就是把人排成隊列,先進先出,解決了資源使用的問題;

排成的隊列,其實就是一個緩沖地帶,就是緩沖區

假設女生優先,那么這個窗口就得是兩隊,只要有女生就先打飯,男生排隊等著,女生隊伍就是一個優先隊列

?

2、爭搶:

只開一個窗口,有可能沒有秩序,也就是誰擠進去就給誰打飯;

擠到窗口的人占據窗口,直到打到飯菜離開;

其他人繼續爭搶,會有一個人正占據窗口,可以視為鎖定窗口,窗口就不能為其他人提供了服務了,這是一種鎖機制

搶到資源就上鎖,排他性鎖,其他人只能等候;

爭搶也是一種高并發解決方案,但不好,因為有可能有人很長時間搶不到;

?

3、預處理:

如果排長隊的原因,是由于每個人打菜等候時間長,因為要吃的菜沒有,需要現做,沒打著飯不走開,鎖定著窗口;

可以提前統計大多數最愛吃的菜品,最愛吃的80%的熱門菜提前做好,保證供應,20%的冷門菜現做;

這樣大多數人,就算鎖定窗口,也很快就釋放窗口了;

一種提前加載用戶需要的數據的思路,預處理思想,緩存常用;

?

4、并行:

成百上千人同時來吃飯,一個隊伍搞不定的,多開打飯窗口形成多個隊列,如同開多個車道一樣,并行打菜;

開窗口就得擴大食堂,得雇人在每一個窗口提供服務,造成成本上升;

日常可通過購買更多服務器,或多開進程實現并行處理,來解決并發問題;

這些都是水平擴展思想;

?

5、提速:

提高單個窗口的打飯速度;

打飯人員提高工作技能,或為單個窗口配備更多的服務人員,都是提速的辦法;

這是一種垂直擴展思想;

?

6、消息中間件:

北京地鐵站外九曲回腸走廊,緩沖人流,進去之后再多口安檢進站;

rabbitmqactivemq(apache)rocketmq(ali apache)kafka(apache)等;

?

以上是最常用的解決方案,一般來說不同的并發場景用不同的策略,而策略可能是多種方式的優化組合;

如,多開食堂(多地),可把食堂建設到宿舍生活區(就近),技術來源于生活;

?

注:

如果線程在單cpu上處理,就不是并行了;

一般server都是多cpu的,服務的部署往往是多機的、分布式的,這都是并行處理;

真正的好系統,是串行、并行共存的;

串行、并行是解決并發的手段之一,不可厚此薄彼;

串行、并行哪個快?問題本身有問題,類似1車道快還是4車道快;

?

?

?

進程和線程:

在實現了線程的OS中,線程是OS能夠進行運算調度的最小單位,它被包含在進程之中,是進程中的實際運作單位,一個程序的執行實例就是一個進程;

?

process,進程:

是計算機中的程序關于某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位,是OS結構的基礎;

?

進程和程序的關系:

程序是源代碼編譯后的文件,而這些文件存放在disk上,當程序被OS加載到內存中,就是進程,進程中存放著指令和數據(資源),它也是線程的容器;

?

linux進程有父進程、子進程;

win的進程是平等關系;

?

thread,線程:

有時被稱為light weight processLWP,輕量級進程,線程是程序執行流的最小單元

一個標準的線程由線程ID、當前指令指針PC、寄存器集合、堆棧組成;

?

processthread理解:

現代OS提出進程的概念,每一個進程都認為自己獨占所有的計算機硬件資源

進程就是獨立的王國,進程間不可以隨便的共享數據;

進程是國,線程是省

線程就是省份,同一個進程內的線程可共享進程的資源,每一個線程擁有自己獨立的堆棧;

進程是容器,進程內的線程是干活的;

線程是程序執行流的最小單元,基本單元是進程;

?

py中的進程和線程:

進程會啟動一個解釋器進程,線程共享一個解釋器進程;

?

?

?

線程的狀態:

ready,就緒態,線程能夠運行,但在等待被調度,可能線程剛剛創建啟動,或剛剛從阻塞中恢復,或被其它線程搶占;

running,運行態,線程正在運行;

blocked,阻塞態,線程等待外部事件發生而無法運行,如IO操作;

terminated,終止,線程完成、或退出、或被取消;


?

?

?

py的線程開發:

使用標準庫threading

?

threading.Thread類:

def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None)

target,線程調用的對象,就是目標函數;

name,為線程起個名,可重名,區分是靠線程ID

args,為目標函數傳遞實參,元組;

kwargs,為目標函數傳遞關鍵字參數,字典;

?

py的線程沒有優先級,沒有線程組的概念,也不能被銷毀、停止、掛起,也就沒有恢復、中斷了;

?

線程啟動:

例:

import threading

import time

?

def worker():

? ??for _ in range(5):

??????? time.sleep(1)

??????? print('welcome magedu')

??? print('thread over')

?

def worker1():

??? for _ in range(5):

??????? time.sleep(1)

??????? print('welcome magedu...')

??? print('thread over...')

?

t = threading.Thread(target=worker, name='w1')?? #實例化一個線程對象

t.start()?? #線程啟動,每個線程必須且只能執行該方法1

# print('~'*30)

# t.start()?? #RuntimeError: threads can only be started oncet.start()只能一次,如果非要再寫一次必須先實例化t=threading.Thread(...)再啟動t.start()

t1 = threading.Thread(target=worker1, name='w2')?? #對于1cpuserver,多線程是假并行

t1.start()

輸出:

welcome magedu...

welcome magedu

welcome magedu...

welcome magedu

welcome magedu...

welcome magedu

welcome magedu...

welcome magedu

welcome magedu...

welcome magedu

thread over

thread over...

?

線程退出:

py沒有提供線程退出的方法,線程在如下情況時退出:

1、線程函數內語句執行完畢;

2、線程函數中拋出未處理的異常;

例:

import threading

import time

?

def worker2():

??? count = 0

??? while True:?? #通過在循環中加標記,當某一變量為指定值時退出循環

??????? time.sleep(1)

??????? print('thread quit')

??????? count += 1

??????? if count > 3:

??????????? raise Exception('new exception')

?

t2 = threading.Thread(target=worker2, name='t2')

t2.start()

輸出:

thread quit

thread quit

thread quit

thread quit

Exception in thread t2:

Traceback (most recent call last):

? File "D:\Python\Python35\lib\threading.py", line 914, in _bootstrap_inner

??? self.run()

? File "D:\Python\Python35\lib\threading.py", line 862, in run

??? self._target(*self._args, **self._kwargs)

? File "E:/git_practice/cmdb/example_threading.py", line 23, in worker2

??? raise Exception('new exception')

Exception: new exception

?

線程的傳參:

本質上就是函數傳參,線程傳參和函數傳參沒什么區別;

例:

import threading

import time

?

def worker3(n):

??? for _ in range(n):

??????? print('thread arguments')

?

# t3 = threading.Thread(target=worker3, name='t3', args=(3,))

t3 = threading.Thread(target=worker3, name='t3', kwargs={'n':3})

t3.start()

輸出:

thread arguments

thread arguments

thread arguments

?

threading的屬性和方法:

current_thread(),返回當前線程對象;

main_thread(),返回主線程對象;

active_count(),當前處于alive狀態(一旦被cpu調度才是活動狀態ready<->running)的線程個數;

enumerate(),返回所有活著的線程的列表,不包括已終止的線程和未開始的線程;

get_ident(),返回當前線程的ID,非0整數;

?

例:

def worker(n=3):

??? print('current_thread: {}'.format(threading.current_thread()))

??? print('current_thread().name: {}'.format(threading.current_thread().name))

??? print('currrent_thread().is_alive(): {}'.format(threading.current_thread().is_alive()))

??? print('main_thread: {}'.format(threading.main_thread()))

??? print('main_thread().is_alive(): {}'.format(threading.main_thread().is_alive()))

??? print('active_count: {}'.format(threading.active_count()))

??? print('enumerate: {}'.format(threading.enumerate()))

?

??? for _ in range(n):

??????? time.sleep(0.5)

??????? print('welcome to magedu')

??? print('thread over')

?

print('current_thread again: {}'.format(threading.current_thread()))

print('current_thread().is_alive() again: {}'.format(threading.current_thread().is_alive()))

?

t = threading.Thread(target=worker,name='w1')

t.start()

# t1 = threading.Thread(target=worker,name='w2')?? #多線程無法確定誰前誰后,每個都有機會被執行到

# t1.start()

輸出:

current_thread again: <_MainThread(MainThread, started 18324)>

current_thread().is_alive() again: True

current_thread: <Thread(w1, started 14036)>

current_thread().name: w1

currrent_thread().is_alive(): True

main_thread: <_MainThread(MainThread, started 18324)>

main_thread().is_alive(): True

active_count: 2

enumerate: [<Thread(w1, started 14036)>, <_MainThread(MainThread, started 18324)>]

welcome to magedu

welcome to magedu

welcome to magedu

thread over

?

Thread實例的屬性和方法:

t.name,只是個名字,是個標識,可重名,getName()獲取,setName()設置;

t.ident,線程ID,是非0整數,線程啟動后才會有ID,否則為None;線程退出,此ID依舊可訪問,此ID可重復使用;t.name可重復,t.ident必須唯一但可在線程退出后再利用;

t.is_alive(),返回線程是否活著,True|False

?

t.start()t.run()

t.start()用于多線程場景,一執行到t1.start()則開啟一個新的工作線程,threading.current_thread()<MyThread(w1, started 17760)>,主線程1個工作線程多個;

t.run(),運行線程函數,僅是普通函數調用,不會開啟新的線程,在當前線程中順序執行,threading.current_thrad()<_MainThread(MainThread, started 15384)>,先執行t1.run()再執行t2.run()

?

注:多線程:

一個進程中有多個線程,實現并發;

一個進程至少有一個主線程,其它線程為工作線程;

一個進程至少有一個線程,作為程序入口,這個線程就是主線程;

多線程爭用同一個資源(打飯時很多人爭一個窗口),解決:加鎖;

父線程不管理子線程,父、子只是為了分清誰啟動的誰;

父線程消亡,子線程仍可繼續運行;

主線程結束時,可殺掉工作線程(子線程);

?

例:

class MyThread(threading.Thread):

??? def run(self):

??????? print('run')

??????? super().run()

?

??? def start(self):

??????? print('start')

??????? return super().start()

?

def worker(n=3):

??? print(threading.current_thread())

??? for _ in range(n):

??????? time.sleep(1)

??????? print('welcome to magedu')

??? print('thread over')

?

t1 = MyThread(target=worker,name='w1')

t1.start()

# t1.run()

# t2 = MyThread(target=worker,name='w2')

# t2.start()

# t2.run()

輸出:

start

run

<MyThread(w1, started 18324)>

welcome to magedu

welcome to magedu

welcome to magedu

thread over

?

線程安全:

多線程的執行結果,有時是意想不到的,即線程不安全,在各種高級語言中都必須面對;

如下例在pycharm中和ipython中分別執行,pycharm中整整齊齊,而ipython中不規整,ipython中運行的效果就是線程不安全;

?

其它語言中有:

線程安全函數;

線程不安全函數(要加鎖);

線程安全類;

線程不安全類(加各種鎖);

?

在多線程或特殊場景下應用,能不加鎖就不加,否則效率極差;

?

例:

def worker():

??? for _ in range(100):

??????? print('{} is running'.format(threading.current_thread()))

?

for _ in range(2):

??? threading.Thread(target=worker,name='worker-{}'.format('view')).start()

解決:

def worker():

??? for _ in range(100):

??????? print('{} is running\n'.format(threading.current_thread()),end='')

?

for _ in range(2):

??? threading.Thread(target=worker,name='worker-{}'.format('view')).start()

?

daemonnon-daemon

linuxdaemon守護進程不一樣linux是進程級別,此處是線程;

進程靠線程執行代碼,至少有一個主線程,其它線程是工作線程;

主線程是第一個啟動的線程;

父線程:如果線程A啟動了線程BAB的父線程;

子線程:BA的子線程;

?

查看Thread類源碼:

??? def __init__(self, group=None, target=None, name=None,

???????????????? args=(), kwargs=None, *, daemon=None):

注:

daemon,沒有主線程之說,都是當前線程;

py構造線程時,可設置daemon屬性,這個屬性必須在t.start()方法前設置好;

?

線程有daemon屬性(僅py有),可顯式設置為TrueFalse;也可不設置取默認值None,如果不設置daemon就取當前線程的daemon來設置它;

主線程是non-daemon線程(鐵律),即daemon=False,從主線程創建的所有線程不設置daemon屬性,則默認都是daemon=Falsenon-daemon線程;

py程序在沒有活著的non-daemon線程運行時退出(主線程kill掉所有活著的daemon線程,主線程退出),也就是剩下的只能是daemon線程,主線程才能退出,否則主線程只能等待(只有在有non-daemon線程,主線程一直等待);

?

daemon屬性,表示線程是否是daemon線程,這個值必須在t.start()前設置,否則引發RuntimeError異常;

isDaemon(),是否是daemon線程;

setDaemon(),設置為daemon線程,必須在t.start()之前設置;

?

簡單來說,本來并沒有daemon thread,為簡化程序員工作,讓他們不用去記錄和管理那些后臺進程,創建了daemon thread概念,這個概念唯一的作用是,當你把一個線程設為daemon,它會隨主線程的退出而退出

daemon線程簡化了程序員手動關閉線程的工作;

?

daemon線程適用場景:

1、后臺任務,如:發送心跳包、監控等場景居多;

2、主線程工作才有用的線程,如主線程中維護著公共的資源,主線程已經清理了,準備退出,而工作線程使用這些資源工作也沒意義了,一起退出最合適;

3、隨時可被終止的線程;

如果主線程退出,想其它工作線程一起退出,就使用daemon=True來創建工作線程;

如,開啟一個線程,定時判斷web服務是否正常工作,主線程退出,工作線程也沒必要存在了,應隨主線程一起退出,這種daemon線程一旦創建,就可忘記它了,只用關心主線程什么時候退出就行;

?

如果在non-daemon線程(A)中,對另一個daemon線程(B)使用了join方法,這個線程B設置daemon就沒意義了,因為Anon-daemon)總是要等待B的;

如果在一個daemon線程C中,對另一個daemon線程D使用了join方法,只能說明C要等待D,主線程退出,CD不管是否結束,也不管它們誰等誰,都要被殺掉;

?

例:

import threading

import logging

logging.basicConfig(level=logging.INFO)

?

def worker():

??? for _ in range(100):

??????? msg = '{} is running'.format(threading.current_thread())

??????? logging.info(msg)?? #logging.info(msg)print()的內容不規律的交替出現,原因:多線程,誰前誰后不可預知,要看cpu運行調度情況

??????? print('inner threading.enumerate(): {}'.format(threading.enumerate()))

?

threading.Thread(target=worker,name='worker-{}'.format('view')).start()?? #工作線程未設置daemon則用主線程的daemon=False(鐵律,主線程是non-daemon),主線程一直等待子線程執行完才退出

print('end')

print('main threading.enumerate(): {}'.format(threading.enumerate()))?? #返回主線程+其它活著的工作線程

輸出:

……

INFO:root:<Thread(worker-view, started 16204)> is running

INFO:root:<Thread(worker-view, started 16204)> is running

end

inner threading.enumerate(): [<_MainThread(MainThread, started 17456)>, <Thread(worker-view, started 16204)>]

main threading.enumerate(): [<_MainThread(MainThread, started 17456)>, <Thread(worker-view, started 16204)>]

……

?

例:

# threading.Thread(target=worker,name='worker-{}'.format('view')).start()

threading.Thread(target=worker,name='worker-{}'.format('view'),daemon=True).start()?? #daemon線程,主線程不會等待,直接殺掉daemon線程退出

print('end')

print('main threading.enumerate(): {}'.format(threading.enumerate()))

?

例:

logging.basicConfig(level=logging.INFO)

?

def worker():

??? threading.Thread(target=worker1,name='worker1-{}'.format('view')).start()?? #取當前線程的daemon,即daemon=True

??? for _ in range(100):

??????? msg = '{} is running'.format(threading.current_thread())

??????? logging.info(msg)

?

def worker1():

??? for _ in range(100):

??????? msg = '$$$ {} is running'.format(threading.current_thread())

??????? logging.info(msg)

?

# threading.Thread(target=worker,name='worker-{}'.format('view')).start()

threading.Thread(target=worker,name='worker-{}'.format('view'),daemon=True).start()

# threading.Thread(target=worker,name='worker-{}'.format('view'),daemon=False).start()?? #一旦該線程執行到了,則主線程一直等待;如果沒有執行到(當前試驗沒有執行不到的情況)主線程直接退出了,如何改?加上time.sleep(0.0005)

# time.sleep(0.0005)

print('ending')

print(threading.enumerate())

?

t.join()

t.join(timeout=None)

join()是線程的標準方法之一;

一個線程中調用另一個線程的join方法,調用者將被阻塞,直到被調用線程終止;

一個線程可被join多次;

調用誰的join方法,就是join誰,就要等誰;

timeout參數很少用,指定調用者等待多久,沒有設置就一直等到被調用線程結束;

?

如果在non-daemon線程(A)中,對另一個daemon線程(B)使用了join方法,這個線程B設置daemon就沒意義了,因為Anon-daemon)總是要等待B的;

如果在一個daemon線程C中,對另一個daemon線程D使用了join方法,只能說明C要等待D,主線程退出,CD不管是否結束,也不管它們誰等誰,都要被殺掉;

?

例:

def worker():

??? for _ in range(50):

??????? msg = '{} is running'.format(threading.current_thread())

??????? logging.info(msg)

??????? t = threading.Thread(target=worker1,name='worker1-{}'.format('view'),daemon=True)

??????? t.start()

??????? # t.join()?? #如果有此句打印行數為5050

?

def worker1():

??? for _ in range(100):

??????? msg = '$$$ {} is running'.format(threading.current_thread())

??????? logging.info(msg)

?

t = threading.Thread(target=worker,name='worker-{}'.format('view'),daemon=True)

t.start()

t.join()?? #可理解為join(t),當前線程是主線程,主線程和t聯合起來,主線程要等t執行完才退出

?

例:

def bar():

??? while True:

??????? time.sleep(1)

??????? print('bar')

?

def foo():

??? print('t1 is daemon= {}'.format(threading.current_thread().isDaemon()))

??? t2 = threading.Thread(target=bar)

??? t2.start()

??? print('t2 is daemon= {}'.format(t2.isDaemon()))

??? t2.join()

?

t1 = threading.Thread(target=foo,daemon=True)

t1.start()

# t1.join()

time.sleep(2)

print('main thread exiting')

注:

等價于t1t2都為daemon=Falsenon-daemon

?

threading.local類:

threading.local學習自java

?

查看threading.local源碼:

class local:?? #注意local首字母為小寫

??? __slots__ = '_local__impl', '__dict__'

???????? ……

??? def __getattribute__(self, name):?? #對象所有屬性均攔截,重新構建字典

?

class _localimpl:

??? def __init__(self):

??????? # The key used in the Thread objects' attribute dicts.

??????? # We keep it a string for speed but make it unlikely to clash with

??????? # a "real" attribute.

??????? self.key = '_threading_local._localimpl.' + str(id(self))

??????? # { id(Thread) -> (ref(Thread), thread-local dict) }

??????? self.dicts = {}

?

threading.local類構建了一個大字典,即{ id(Thread) -> (ref(Thread), thread-local dict) },其元素的key是線程實例的內存地址,其元素的value是二元組,二元組中的元素為(線程對象引用+每個線程的字典)

使用時:

d[key][0].name

d[key][1][key]

?

通過threading.local()實例就可在不同線程中,安全的使用線程獨有的數據,做到了線程間數據隔離,如同本地變量一樣安全;

?

多線程中,能不共享就不共享,用局部變量,局部變量與threading.local()比,局部變量用得多些;例如,外面傳進來的參數,直接賦給本地變量,但對于引用類型來說不行(編程中經常遇到外面傳來的是對象,該對象通常是類型);

?

例:

def worker():

??? x = 0

??? for _ in range(100):

??????? time.sleep(0.0001)

??????? x += 1

??? print(threading.current_thread(),x)

?

for _ in range(5):

??? threading.Thread(target=worker).start()?? #線程有自己的棧,每個線程壓棧的x為函數內局部作用域(局部變量),因此多線程里看到最終x值均為100

輸出:

<Thread(Thread-1, started 11216)> 100

<Thread(Thread-5, started 17792)> 100

<Thread(Thread-3, started 15924)> 100

<Thread(Thread-4, started 3248)> 100

<Thread(Thread-2, started 17804)> 100

?

例:

class A:

??? def __init__(self,x):

??????? self.x = x

?

a = A(0) ??#解決此問題(使用全局變量,還能保持每個線程使用不同的數據)

def worker():

??? a.x = 0

??? for _ in range(100):

??????? time.sleep(0.0001)

??????? a.x += 1

??? print(threading.current_thread(),a.x)

??? print(a.__dict__)?? #每個線程有自己的字典,是隔離的

?

for _ in range(5):

??? threading.Thread(target=worker).start()?? #亂,不可預知,使用了全局對象,線程之間互相干擾,導致是錯誤的結果

輸出:

<Thread(Thread-1, started 18216)> 483

<Thread(Thread-3, started 15560)> 493

<Thread(Thread-5, started 17464)> 496

<Thread(Thread-2, started 18268)> 497

<Thread(Thread-4, started 4676)> 498

?

例:

a = threading.local()

?

def worker():

?? ?a.x = 0

??? for _ in range(100):

??????? time.sleep(0.0001)

??????? a.x += 1

??? print(threading.current_thread(),a.x)

???????? print(a.__dict__)?? #每個線程有自己的字典,是隔離的

?

for _ in range(5):

??? threading.Thread(target=worker).start()?? #結果與使用局部變量效果一樣

輸出:

<Thread(Thread-4, started 11792)> 100

<Thread(Thread-2, started 12848)> 100

<Thread(Thread-1, started 17764)> 100

<Thread(Thread-3, started 16464)> 100

<Thread(Thread-5, started 16704)> 100

?

例:

X = 'abc'

ctx = threading.local()

ctx.x = 123

print(ctx,type(ctx),ctx.x)

?

def worker():

??? print(X)

??? print(ctx)

? ??print(ctx.x)

??? print('good job')

?

worker()

print('~'*30)

threading.Thread(target=worker).start()?? #ctx.x出錯,AttributeError,要在worker中重新定義ctx.x=567

輸出:

<_thread._local object at 0x000000000125DA40> <class '_thread._local'> 123

abc

<_thread._local object at 0x000000000125DA40>

123

good job

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

abc

<_thread._local object at 0x000000000125DA40>

Exception in thread Thread-1:

Traceback (most recent call last):

? File "D:\Python\Python35\lib\threading.py", line 914, in _bootstrap_inner

??? self.run()

? File "D:\Python\Python35\lib\threading.py", line 862, in run

??? self._target(*self._args, **self._kwargs)

? File "E:/git_practice/cmdb/example_threading.py", line 215, in worker

??? print(ctx.x)

AttributeError: '_thread._local' object has no attribute 'x'

?

threading.Timer類:

定時器,延遲執行,定義多久執行一個函數,繼承自threading.Thread

?

查看源碼:

??? def __init__(self, interval, function, args=None, kwargs=None):

t.start()方法執行后,Timer()對象處于等待狀態,等待interval后,開始執行function,實際是延遲執行該線程而不是函數;

non-daemon,繼承Thread

TimerThread的子類,就是線程類,具有線程的能力和特征;它的實例是能夠延時執行目標函數的線程,在真正執行目標函數之前都可cancel它;

?

t.cancel()

如果在執行函數之前的等待階段使用了t.cancel()方法,就會跳過,函數不會執行;

并不是非要在t.start()之后,只要在延遲時間內取消都可以;

查看源碼,通過event實現t.cancel()

?

例:

# def add():

#???? print(4 + 5)

#???? print(threading.enumerate())

# t = threading.Timer(3,add)

# t.setName('w1')

# t.start()

?

def add(x,y):

??? print(x + y)

??? print(threading.enumerate())

t1 = threading.Timer(2,add,args=(4,4))

t1.setName('w2')

t1.start()

# t1.cancel()?? #此句可不在t.start()之后,只要在延遲時間內取消都可以;如果線程中add函數已經開始執行了,cancel就沒任何效果了

print(threading.enumerate())

time.sleep(3)

t1.cancel()?? #此時取消無效,3>2add函數已經執行

輸出:

[<_MainThread(MainThread, started 14560)>, <Timer(w2, started 17696)>]

8

[<_MainThread(MainThread, started 14560)>, <Timer(w2, started 17696)>]

?

?


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

伊川县| 蕉岭县| 莲花县| 洛南县| 四子王旗| 彭阳县| 二连浩特市| 万安县| 河北省| 黔江区| 丰都县| 康平县| 梓潼县| 平泉县| 龙门县| 九龙县| 综艺| 南京市| 桂平市| 蓝田县| 吉水县| 洪江市| 云浮市| 宁远县| 桓台县| 靖安县| 新乡市| 砀山县| 永安市| 慈利县| 涿州市| 昆山市| 盱眙县| 玛多县| 尉犁县| 新源县| 青铜峡市| 通州区| 临武县| 蓬安县| 通许县|