1.線程
Python中使用線程有兩種方式:函數(shù)或者用類來包裝線程對(duì)象若贮。
1.函數(shù)式:調(diào)用thread模塊中的start_new_thread()函數(shù)來產(chǎn)生新線程谐宙。
語(yǔ)法如下:
thread.start_new_thread(function,args[,kwargs])
參數(shù)說明:
function - 線程函數(shù)颜武。
args - 傳遞給線程函數(shù)的參數(shù),他必須是個(gè)tuple類型。
kwargs - 可選參數(shù)。
2.線程模塊
Python通過兩個(gè)標(biāo)準(zhǔn)庫(kù)thread和threading提供對(duì)線程的支持籽孙。thread提供了低級(jí)別的会钝、原始的線程以及一個(gè)簡(jiǎn)單的鎖伐蒋。
thread 模塊提供的其他方法:
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é)果掸读。
除了使用方法外,線程模塊同樣提供了Thread類來處理線程闹蒜,Thread類提供了以下方法:
run():用以表示線程活動(dòng)的方法寺枉。
start():啟動(dòng)線程活動(dòng)。
join([time]):等待至線程中止绷落。這阻塞調(diào)用線程直至線程的join() 方法被調(diào)用中止-正常退出或者拋出未處理的異常-或者是可選的超時(shí)發(fā)生姥闪。
isAlive():返回線程是否活動(dòng)的。
getName():返回線程名砌烁。
setName():設(shè)置線程名筐喳。
3.線程優(yōu)先級(jí)隊(duì)列( Queue)
Python的Queue模塊中提供了同步的、線程安全的隊(duì)列類函喉,包括FIFO(先入先出)隊(duì)列Queue避归,LIFO(后入先出)隊(duì)列LifoQueue,和優(yōu)先級(jí)隊(duì)列PriorityQueue管呵。這些隊(duì)列都實(shí)現(xiàn)了鎖原語(yǔ)梳毙,能夠在多線程中直接使用【柘拢可以使用隊(duì)列來實(shí)現(xiàn)線程間的同步账锹。
Queue模塊中的常用方法:
Queue.qsize() 返回隊(duì)列的大小
Queue.empty() 如果隊(duì)列為空,返回True,反之False
Queue.full() 如果隊(duì)列滿了坷襟,返回True,反之False
Queue.full 與 maxsize 大小對(duì)應(yīng)
Queue.get([block[, timeout]])獲取隊(duì)列奸柬,timeout等待時(shí)間
Queue.get_nowait() 相當(dāng)Queue.get(False)
Queue.put(item) 寫入隊(duì)列,timeout等待時(shí)間
Queue.put_nowait(item) 相當(dāng)Queue.put(item, False)
Queue.task_done() 在完成一項(xiàng)工作之后婴程,Queue.task_done()函數(shù)向任務(wù)已經(jīng)完成的隊(duì)列發(fā)送一個(gè)信號(hào)
Queue.join() 實(shí)際上意味著等到隊(duì)列為空廓奕,再執(zhí)行別的操作
2.多線程-threading
python的thread模塊是比較底層的模塊,python的threading模塊是對(duì)thread做了一些包裝的档叔,可以更加方便的被使用
1.使用threading模塊
單線程執(zhí)行:
多線程執(zhí)行:
說明:
1.可以明顯看出使用了多線程并發(fā)的操作桌粉,花費(fèi)時(shí)間要短很多
2.創(chuàng)建好的線程,需要調(diào)用start()方法來啟動(dòng)
3.主線程會(huì)等待所有的子線程結(jié)束后才結(jié)束
4.查看線程數(shù)量
我們可以通過用threading.enumerate()來查看線程的數(shù)量
5.threading注意點(diǎn)
1.線程執(zhí)行代碼的封裝
通過上一小節(jié)衙四,能夠看出铃肯,通過使用threading模塊能完成多任務(wù)的程序開發(fā),為了讓每個(gè)線程的封裝性更完美届搁,所以使用threading模塊時(shí),往往會(huì)定義一個(gè)新的子類class,只要繼承threading.Thread就可以了卡睦,然后重寫run方法
threading.Thread
Thread是threading模塊中最重要的類之一宴胧,可以使用它來創(chuàng)建線程。有兩種方式來創(chuàng)建線程:一種是通過繼承Thread類表锻,重寫它的run方法恕齐;另一種是創(chuàng)建一個(gè)threading.Thread對(duì)象,在它的初始化函數(shù)(__init__)中將可調(diào)用對(duì)象作為參數(shù)傳入瞬逊。
·python的threading.Thread類有一個(gè)run方法显歧,用于定義線程的功能函數(shù),可以在自己的線程類中覆蓋該方法确镊。而創(chuàng)建自己的線程實(shí)例后士骤,通過Thread類的start方法,可以啟動(dòng)該線程蕾域,交給python虛擬機(jī)進(jìn)行調(diào)度拷肌,當(dāng)該線程獲得執(zhí)行的機(jī)會(huì)時(shí),就會(huì)調(diào)用run方法執(zhí)行線程旨巷。
def__init__(self, group=None, target=None, name=None, args=(), kwargs={})
1.參數(shù)group是預(yù)留的巨缘,用于將來擴(kuò)展;
2.參數(shù)target是一個(gè)可調(diào)用對(duì)象(也稱為活動(dòng)[activity])采呐,在線程啟動(dòng)后執(zhí)行若锁;
3.參數(shù)name是線程的名字。默認(rèn)值為“Thread-N“斧吐,N是一個(gè)數(shù)字又固。
4.參數(shù)args和kwargs分別表示調(diào)用target時(shí)的參數(shù)列表和關(guān)鍵字參數(shù)。
5.Thread類還定義了以下常用方法與屬性:
1.Thread.getName()
2.Thread.setName()
3.Thread.name
用于獲取和設(shè)置線程的名稱会通。
Thread.ident
獲取線程的標(biāo)識(shí)符口予。線程標(biāo)識(shí)符是一個(gè)非零整數(shù),只有在調(diào)用了start()方法之后該屬性才有效涕侈,否則它只返回None沪停。
1.Thread.is_alive()
2.Thread.isAlive()
判斷線程是否是激活的(alive)。從調(diào)用start()方法啟動(dòng)線程裳涛,到run()方法執(zhí)行完畢或遇到未處理異常而中斷 這段時(shí)間內(nèi)木张,線程是激活的。
Thread.join([timeout])
調(diào)用Thread.join將會(huì)使主調(diào)線程堵塞端三,直到被調(diào)用線程運(yùn)行結(jié)束或超時(shí)舷礼。參數(shù)timeout是一個(gè)數(shù)值類型,表示超時(shí)時(shí)間郊闯,如果未提供該參數(shù)妻献,那么主調(diào)線程將一直堵塞到被調(diào)線程結(jié)束蛛株。
由于任何進(jìn)程默認(rèn)就會(huì)啟動(dòng)一個(gè)線程,我們把該線程稱為主線程育拨,主線程又可以啟動(dòng)新的線程谨履,Python的threading模塊有個(gè)current_thread()函數(shù),它永遠(yuǎn)返回當(dāng)前線程的實(shí)例熬丧。主線程實(shí)例的名字叫MainThread笋粟,子線程的名字在創(chuàng)建時(shí)指定,我們用LoopThread命名子線程析蝴。名字僅僅在打印時(shí)用來顯示害捕,完全沒有其他意義,如果不起名字Python就自動(dòng)給線程命名為Thread-1闷畸,Thread-2……
2.線程的執(zhí)行順序
說明
從代碼和執(zhí)行結(jié)果我們可以看出尝盼,多線程程序的執(zhí)行順序是不確定的。當(dāng)執(zhí)行到sleep語(yǔ)句時(shí)腾啥,線程將被阻塞(Blocked)东涡,到sleep結(jié)束后,線程進(jìn)入就緒(Runnable)狀態(tài)倘待,等待調(diào)度疮跑。而線程調(diào)度將自行選擇一個(gè)線程執(zhí)行。上面的代碼中只能保證每個(gè)線程都運(yùn)行完整個(gè)run函數(shù)凸舵,但是線程的啟動(dòng)順序祖娘、run函數(shù)中每次循環(huán)的執(zhí)行順序都不能確定。
總結(jié)
1.每個(gè)線程一定會(huì)有一個(gè)名字啊奄,盡管上面的例子中沒有指定線程對(duì)象的name渐苏,但是python會(huì)自動(dòng)為線程指定一個(gè)名字。
2.當(dāng)線程的run()方法結(jié)束時(shí)該線程完成菇夸。
3.無法控制線程調(diào)度程序琼富,但可以通過別的方式來影響線程調(diào)度的方式。
4.線程的幾種狀態(tài)
6.多線程-共享全局變量
7.列表當(dāng)做實(shí)參傳遞到線程中
·在一個(gè)進(jìn)程內(nèi)的所有線程共享全局變量庄新,能夠在不適用其他方式的前提下完成多線程之間的數(shù)據(jù)共享(這點(diǎn)要比多進(jìn)程要好)
·缺點(diǎn)就是鞠眉,線程是對(duì)全局變量隨意遂改可能造成多線程之間對(duì)全局變量的混亂(即線程非安全)