python多线程理解
在發(fā)送網(wǎng)絡(luò)請(qǐng)求的過(guò)程中,單個(gè)請(qǐng)求的速度總是有著很大的限制,而任務(wù)往往需要以更快的速度去執(zhí)行,這時(shí)多線程就是一個(gè)很好地選擇。python已經(jīng)給我們封裝好了多線程庫(kù)thread和threading。
thread:比較底層的模塊
threading:Higher-level threading interface
ps:建議使用threading模塊
- 高級(jí)別的threading模塊更為先進(jìn),對(duì)線程的支持更為完善
- 低級(jí)別的thread模塊同步原語(yǔ)很少
- thread模塊對(duì)線程什么時(shí)候結(jié)束完全沒(méi)有控制,當(dāng)主線程結(jié)束時(shí),所有線程都會(huì)強(qiáng)制結(jié)束
thread
模塊函數(shù)
start_new_thread(function, args,kwargs=None): 產(chǎn)生新的線程,args是function的參數(shù),沒(méi)有時(shí)寫(xiě)(),kwargs用來(lái)調(diào)用這個(gè)函數(shù)
allocate_lock(): 分配鎖,LockType類型
exit(): 讓線程退出
LockType的操作
acquire(wait=None):嘗試獲取鎖
locked(): 獲取了鎖返回True,沒(méi)有返回False
release():釋放鎖
Demo1
$ cat t1.py
import thread
from time import sleep
def a():
print "a start"
sleep(2)
print "a end"
def b():
print "b start"
sleep(2)
print "b end"
def main():
thread.start_new_thread(a,())
thread.start_new_thread(b,())
print "all done"
if __name__ == "__main__":
main()
$ python t1.py
all done
b start
a start
最終會(huì)發(fā)現(xiàn),每一次運(yùn)行出來(lái)的結(jié)果都有可能不同,但是絕對(duì)不會(huì)出現(xiàn)“a end”和“b end”。這是為什么呢,這里沒(méi)有寫(xiě)讓主線程停下來(lái)等所有子線程結(jié)束后再繼續(xù)運(yùn)行的代碼,所以main線程在執(zhí)行完print "all done"就關(guān)閉了a和b兩個(gè)線程。怎么辦呢,可以在這里加一個(gè)sleep等待子進(jìn)程執(zhí)行完畢后再退出。
Demo2: thread -- 多線程的演示 by sleep
$ cat t2.py
import thread
from time import sleep
def a():
print "a start"
sleep(2)
print "a end"
def b():
print "b start"
sleep(2)
print "b end"
def main():
thread.start_new_thread(a,())
thread.start_new_thread(b,())
sleep (4) ----防止主進(jìn)程過(guò)早退出,加sleep等待子進(jìn)程執(zhí)行完畢后再推出
print "all done"
if __name__ == "__main__":
main()
$ python t1.py
b start
a start
a end
b end
all done
但是假設(shè)我們不知道子進(jìn)程執(zhí)行的時(shí)間怎么辦,這就是鎖的用武之地了。因?yàn)槭褂面i要比使用sleep()函數(shù)更為合理。如下所示:
Demo3: thread -- 多線程演示 by lock
實(shí)現(xiàn)方式為: 主線程初始化兩個(gè)鎖,分別傳給兩個(gè)函數(shù),兩個(gè)函數(shù)在執(zhí)行完自己的代碼后釋放鎖,主線程一直在輪詢這個(gè)鎖有沒(méi)有釋放,如果釋放了就退出。
def a(lock, nsec):
print "a starting at :", ctime()
sleep(nsec)
lock.release() -- 執(zhí)行完之后釋放鎖
print "a end", ctime()
def b(lock, nsec):
print "b starting at :", ctime()
sleep(nsec)
lock.release() -- 執(zhí)行完之后釋放鎖
print "b end", ctime()
def main():
print "Demo Starting at:", ctime()
locks = []
# Initialize lock -- 主線程先獲取兩個(gè)鎖,占為己有
for i in range(2):
lock = thread.allocate_lock()
lock.acquire()
locks.append(lock)
# 每個(gè)進(jìn)程分配一個(gè)鎖
thread.start_new_thread(a, (locks[0],2))
thread.start_new_thread(b, (locks[1],4))
for i in range(2): #一直在輪詢,看鎖有沒(méi)有釋放
while locks[i].locked(): pass
print "all done at:", ctime()
最后的結(jié)果為:
$ python thread_demo.py
Demo Starting at: Fri Aug 29 22:03:01 2014
a starting at : Fri Aug 29 22:03:01 2014
b starting at : Fri Aug 29 22:03:01 2014
a end Fri Aug 29 22:03:03 2014
b end Fri Aug 29 22:03:05 2014
all done at: Fri Aug 29 22:03:05 2014
不難發(fā)現(xiàn),thread庫(kù)的同步機(jī)制比較難用,一切都需要主進(jìn)程來(lái)處理。并且沒(méi)有守護(hù)進(jìn)程,主進(jìn)程一退,整個(gè)世界都會(huì)變得很清靜。而threading庫(kù)給我們提供了守護(hù)進(jìn)程。下面就來(lái)看看threading的簡(jiǎn)單用法。
threading
threading提供了Thread類,還提供了很多非常好用的同步機(jī)制。感覺(jué)重點(diǎn)了解Thread類就可以,多線程,也就是通過(guò)Thread類的多個(gè)實(shí)例。 類的主要方法有:
start():開(kāi)始線程的執(zhí)行。thread庫(kù)里里面,是沒(méi)有辦法控制線程的開(kāi)始的
join(timeout=None): 等待線程結(jié)束,有點(diǎn)類似Demo3中的輪詢
run():定義線程的功能
感覺(jué)上面是比較重要的,立馬就會(huì)用到的。還有一些其他的:
getName():獲取線程名
setName(name):設(shè)置線程名
isAlive(): 返回bool 表示線程是否在運(yùn)行中
activeCount():返回運(yùn)行中的線程數(shù)
currentThread():返回當(dāng)前線程對(duì)象
enumerate():返回當(dāng)前活動(dòng)線程的列表
isDaemon(): 返回線程的Daemon標(biāo)志
setDaemon(daemonic): 設(shè)置線程的Daemon標(biāo)志,一般在start()函數(shù)前調(diào)用
settrace(func):為所有線程設(shè)置跟蹤函數(shù)
setprofile(func): 為所有線程設(shè)置profile函數(shù)
Demo4 -- threading演示
def loop(i, nsec):
print "thread %d starting at : %s" %(i, ctime())
sleep(nsec)
print "thread %d end at : %s" %(i, ctime())
def main():
threads = []
loops = [2, 4]
# 實(shí)例化進(jìn)程
for i in range(len(loops)):
t = threading.Thread(target = loop, args = (i, loops[i]))
threads.append(t)
for i in range(len(loops)):
threads[i].start()
for i in range(len(loops)):
threads[i].join()
print "all done"
最后的結(jié)果為:
thread 0 starting at : Sun Aug 31 13:31:28 2014
thread 1 starting at : Sun Aug 31 13:31:28 2014
thread 0 end at : Sun Aug 31 13:31:30 2014
thread 1 end at : Sun Aug 31 13:31:32 2014
all done
對(duì)Daemon線程理解:
A thread can be flagged as a “daemon thread”. The significance of this flag is that the entire Python program exits when only daemon threads are left. The initial value is inherited from the creating thread. The flag can be set through the daemon property.
線程可以被標(biāo)識(shí)為"Daemon線程",Daemon線程表明整個(gè)Python主程序只有在Daemon子線程運(yùn)行時(shí)可以退出。該屬性值繼承自父線程,可通過(guò)setDaemon()函數(shù)設(shè)定該值。
Daemon threads are abruptly stopped at shutdown. Their resources (such as open files, database transactions, etc.) may not be released properly. If you want your threads to stop gracefully, make them non-daemonic and use a suitable signalling mechanism such as an Event.
注意:Daemon線程會(huì)被粗魯?shù)闹苯咏Y(jié)束,它所使用的資源(已打開(kāi)文件、數(shù)據(jù)庫(kù)事務(wù)等)無(wú)法被合理的釋放。因此如果需要線程被優(yōu)雅的結(jié)束,請(qǐng)?jiān)O(shè)置為非Daemon線程,并使用合理的信號(hào)方法,如事件Event。
Python主程序當(dāng)且僅當(dāng)不存在非Daemon線程存活時(shí)退出。
即:主程序等待所有非Daemon線程結(jié)束后才退出,且退出時(shí)會(huì)自動(dòng)結(jié)束(很粗魯?shù)慕Y(jié)束)所有Daemon線程。
亦理解為:Daemon設(shè)置為子線程是否隨主線程一起結(jié)束,默認(rèn)為False。如果要隨主線程一起結(jié)束需要設(shè)置為T(mén)rue。
Daemon線程用途:
Daemons are only useful when the main program is running, and it's okay to kill them off once the other non-daemon threads have exited. Without daemon threads, we have to keep track of them, and tell them to exit, before our program can completely quit. By setting them as daemon threads, we can let them run and forget about them, and when our program quits, any daemon threads are killed automatically.
Daemon線程當(dāng)且僅當(dāng)主線程運(yùn)行時(shí)有效,當(dāng)其他非Daemon線程結(jié)束時(shí)可自動(dòng)殺死所有Daemon線程。如果沒(méi)有Daemon線程的定義,則必須手動(dòng)的跟蹤這些線程,在程序結(jié)束前手動(dòng)結(jié)束這些線程。通過(guò)設(shè)置線程為Daemon線程,則可以放任它們運(yùn)行,并遺忘它們,當(dāng)主程序結(jié)束時(shí)這些Daemon線程將自動(dòng)被殺死。
轉(zhuǎn)載于:https://www.cnblogs.com/niansi/p/7441582.html
總結(jié)
以上是生活随笔為你收集整理的python多线程理解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: [js高手之路]原型对象(prototy
- 下一篇: Python学习笔记(四十六)网络编程(