線程
1.1.1 多線程——threading
python的thread模塊是比較底層的模塊,python的threading模塊是對thread做了一些包裝的,可以更加方便的被使用
1.1.2 使用threading模塊
單線程執(zhí)行
importtime
defsaySorry():
print("親愛的,我錯了,我能吃飯了嗎?")
time.sleep(1)
if__name__ =="__main__":
foriinrange(5):
saySorry()
多線程執(zhí)行
importthreading
importtime
defsaySorry():
print("親愛的,我錯了,我能吃飯了嗎?")
time.sleep(1)
if__name__ =="__main__":
foriinrange(5):
t = threading.Thread(target=saySorry)
t.start()#啟動線程,即讓線程開始執(zhí)行
說明
1.可以明顯看出使用了多線程并發(fā)的操作,花費時間要短很多
2.創(chuàng)建好的線程,需要調用start()方法來啟動
1.1.3 主線程會等待所有子線程結束后才結束
importthreading
fromtimeimportsleep,ctime
defsing():
foriinrange(3):
print("正在唱歌...%d"%i)
sleep(1)
defdance():
foriinrange(3):
print("正在跳舞...%d"%i)
sleep(1)
if__name__ =='__main__':
print('---開始---:%s'%ctime())
t1 = threading.Thread(target=sing)
t2 = threading.Thread(target=dance)
t1.start()
t2.start()
#sleep(5) #屏蔽此行代碼,試試看,程序是否會立馬結束?
print('---結束---:%s'%ctime())
1.1.4 查看線程數(shù)量
importthreading
fromtimeimportsleep,ctime
defsing():
foriinrange(3):
print("正在唱歌...%d"%i)
sleep(1)
defdance():
foriinrange(3):
print("正在跳舞...%d"%i)
sleep(1)
if__name__ =='__main__':
print('---開始---:%s'%ctime())
t1 = threading.Thread(target=sing)
t2 = threading.Thread(target=dance)
t1.start()
t2.start()
whileTrue:
length = len(threading.enumerate())
print('當前運行的線程數(shù)為:%d'%length)
iflength<=1:
break
sleep(0.5)
1.2 threating注意點
1.2.1 線程執(zhí)行代碼的封裝
通過上一小節(jié),能夠看出,通過使用threading模塊能完成多任務的程序開發(fā),為了讓每個線程的封裝性更完美,所以使用threading模塊時,往往會定義一個新的子類class,只要繼承threading.Thread就可以了,然后重寫run方法
示例如下:
importthreading
importtime
classMyThread(threading.Thread):
defrun(self):
foriinrange(3):
time.sleep(1)
msg ="I'm "+self.name+' @ '+str(i)#name屬性中保存的是當前線程的名字
print(msg)
if__name__ =='__main__':
t = MyThread()
t.start()
說明
·python的threading.Thread類有一個run方法,用于定義線程的功能函數(shù),可以在自己的線程類中覆蓋該方法。而創(chuàng)建自己的線程實例后,通過Thread類的start方法,可以啟動該線程,交給python虛擬機進行調度,當該線程獲得執(zhí)行的機會時,就會調用run方法執(zhí)行線程。
1.2.1 線程的執(zhí)行順序
#coding=utf-8
importthreading
importtime
classMyThread(threading.Thread):
defrun(self):
foriinrange(3):
time.sleep(1)
msg ="I'm "+self.name+' @ '+str(i)
print(msg)
deftest():
foriinrange(5):
t = MyThread()
t.start()
if__name__ =='__main__':
test()
執(zhí)行結果:(運行的結果可能不一樣,但是大體是一致的)
I'm Thread-1 @ 0
I'm Thread-2 @ 0
I'm Thread-5 @ 0
I'm Thread-3 @ 0
I'm Thread-4 @ 0
I'm Thread-3 @ 1
I'm Thread-4 @ 1
I'm Thread-5 @ 1
I'm Thread-1 @ 1
I'm Thread-2 @ 1
I'm Thread-4 @ 2
I'm Thread-5 @ 2
I'm Thread-2 @ 2
I'm Thread-1 @ 2
I'm Thread-3 @ 2
說明
從代碼和執(zhí)行結果我們可以看出,多線程程序的執(zhí)行順序是不確定的。當執(zhí)行到sleep語句時,線程將被阻塞(Blocked),到sleep結束后,線程進入就緒(Runnable)狀態(tài),等待調度。而線程調度將自行選擇一個線程執(zhí)行。上面的代碼中只能保證每個線程都運行完整個run函數(shù),但是線程的啟動順序、run函數(shù)中每次循環(huán)的執(zhí)行順序都不能確定。
總結
1.每個線程一定會有一個名字,盡管上面的例子中沒有指定線程對象的name,但是python會自動為線程指定一個名字。
2.當線程的run()方法結束時該線程完成。
3.無法控制線程調度程序,但可以通過別的方式來影響線程調度的方式。
4.線程的幾種狀態(tài)

1.3 多線程-共享全局變量
fromthreadingimportThread
importtime
g_num =100
defwork1():
globalg_num
foriinrange(3):
g_num +=1
print("----in work1, g_num is %d---"%g_num)
defwork2():
globalg_num
print("----in work2, g_num is %d---"%g_num)
print("---線程創(chuàng)建之前g_num is %d---"%g_num)
t1 = Thread(target=work1)
t1.start()
#延時一會,保證t1線程中的事情做完
time.sleep(1)
t2 = Thread(target=work2)
t2.start()
運行結果:
---線程創(chuàng)建之前g_numis100---
----inwork1, g_numis103---
----inwork2, g_numis103---
列表當做實參傳遞到線程中
fromthreadingimportThread
importtime
defwork1(nums):
nums.append(44)
print("----in work1---",nums)
defwork2(nums):
#延時一會,保證t1線程中的事情做完
time.sleep(1)
print("----in work2---",nums)
g_nums = [11,22,33]
t1 = Thread(target=work1, args=(g_nums,))
t1.start()
t2 = Thread(target=work2, args=(g_nums,))
t2.start()
運行結果:
----inwork1--- [11,22,33,44]
----inwork2--- [11,22,33,44]
總結:
·在一個進程內的所有線程共享全局變量,能夠在不適用其他方式的前提下完成多線程之間的數(shù)據共享(這點要比多進程要好)
·缺點就是,線程是對全局變量隨意遂改可能造成多線程之間對全局變量的混亂(即線程非安全)
1.4 進程vs 線程
1.4.1 功能
·進程,能夠完成多任務,比如在一臺電腦上能夠同時運行多個QQ
·線程,能夠完成多任務,比如一個QQ中的多個聊天窗口
1.4.2 定義的不同
·進程是系統(tǒng)進行資源分配和調度的一個獨立單位.
·線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程自己基本上不擁有系統(tǒng)資源,只擁有一點在運行中必不可少的資源(如程序計數(shù)器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源.
1.4.3 區(qū)別
·一個程序至少有一個進程,一個進程至少有一個線程.
·線程的劃分尺度小于進程(資源比進程少),使得多線程程序的并發(fā)性高。
·進程在執(zhí)行過程中擁有獨立的內存單元,而多個線程共享內存,從而極大地提高了程序的運行效率
·線程不能夠獨立執(zhí)行,必須依存在進程中
1.4.4 優(yōu)缺點
線程和進程在使用上各有優(yōu)缺點:線程執(zhí)行開銷小,但不利于資源的管理和保護;而進程正相反。