1.使用threading模塊python
#coding=utf-8 import threading import time def saySorry(): print("親愛的,我錯了,我能吃飯了嗎?") time.sleep(1) if __name__ == "__main__": for i in range(5): t = threading.Thread(target=saySorry) t.start() #啓動線程,即讓線程開始執⾏
說明
1. 能夠明顯看出使⽤了多線程併發的操做,花費時間要短不少
2. 建立好的線程,須要調⽤ start() ⽅法來啓動數據庫
2.主線程會等待全部的⼦線程結束後才結束設計模式
#coding=utf-8 import threading from time import sleep,ctime def sing(): for i in range(3): print("正在唱歌...%d"%i) sleep(1) def dance(): for i in range(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())
3.查看線程數量安全
while True: length = len(threading.enumerate()) print('當前運⾏的線程數爲:%d'%length) if length<=1: break
4.run()方法寫多線程
#coding=utf-8 import threading import time class MyThread(threading.Thread): def run(self): for i in range(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⽅法,⽤於定義線程的功能函
數,能夠在⾃⼰的線程類中覆蓋該⽅法。⽽建立⾃⼰的線程實例後,通
過Thread類的start⽅法,能夠啓動該線程,交給python虛擬機進⾏調
度,當該線程得到執⾏的機會時,就會調⽤run⽅法執⾏線程。併發
5.線程的執行順序app
#coding=utf-8 import threading import time class MyThread(threading.Thread): def run(self): for i in range(3): time.sleep(1) msg = "I'm "+self.name+' @ '+str(i) print(msg) def test(): for i in range(5): t = MyThread() t.start() if __name__ == '__main__': test()
說明
從代碼和執⾏結果咱們能夠看出,多線程程序的執⾏順序是不肯定的。當執
⾏到sleep語句時,線程將被阻塞(Blocked),到sleep結束後,線程進⼊就
緒(Runnable)狀態,等待調度。⽽線程調度將⾃⾏選擇⼀個線程執⾏。上
⾯的代碼中只能保證每一個線程都運⾏完整個run函數,可是線程的啓動順序、
run函數中每次循環的執⾏順序都不能肯定。函數
6.線程的幾種狀態ui
7.多線程-共享全局變量spa
from threading import Thread import time g_num = 100 def work1(): global g_num for i in range(3): g_num += 1 print("----in work1, g_num is %d---"%g_num) def work2(): global g_num print("----in work2, g_num is %d---"%g_num) print("---線程建立以前g_num is %d---"%g_num) t1 = Thread(target=work1) t1.start() #延時⼀會,保證t1線程中的事情作完 time.sleep(1) t2 = Thread(target=work2) t2.start()
8.列表當中參數傳遞到線程中
from threading import Thread import time def work1(nums): nums.append(44) print("----in work1---",nums) def work2(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() 運⾏結果: ----in work1--- [11, 22, 33, 44] ----in work2--- [11, 22, 33, 44]
缺點就是,線程是對全局變量隨意遂改可能形成多線程之間對全局變量
的混亂(即線程⾮安全)
9.進程 VS 線程
功能
·進程,可以完成多任務,⽐如 在⼀臺電腦上可以同時運⾏多個QQ
·線程,可以完成多任務,⽐如 ⼀個QQ中的多個聊天窗⼝
定義的不一樣
·進程是系統進⾏資源分配和調度的⼀個獨⽴單位.
·線程是進程的⼀個實體,是CPU調度和分派的基本單位,它是⽐進程更⼩的
能獨⽴運⾏的基本單位.線程⾃⼰基本上不擁有系統資源,只擁有⼀點在運
⾏中必不可少的資源(如程序計數器,⼀組寄存器和棧),可是它可與同屬⼀
個進程的其餘的線程共享進程所擁有的所有資源.
區別
·⼀個程序⾄少有⼀個進程,⼀個進程⾄少有⼀個線程.
·線程的劃分尺度⼩於進程(資源⽐進程少),使得多線程程序的併發性⾼。
·進程在執⾏過程當中擁有獨⽴的內存單元,⽽多個線程共享內存,從⽽極
⼤地提⾼了程序的運⾏效率
·線線程不可以獨⽴執⾏,必須依存在進程中
優缺點
線程和進程在使⽤上各有優缺點:線程執⾏開銷⼩,但不利於資源的管理和
保護;⽽進程正相反。
10.互斥鎖
當多個線程⼏乎同時修改某⼀個共享數據的時候,須要進⾏同步控制
線程同步可以保證多個線程安全訪問競爭資源,最簡單的同步機制是引⼊互
斥鎖。
互斥鎖爲資源引⼊⼀個狀態:鎖定/⾮鎖定。
threading模塊中定義了Lock類,能夠⽅便的處理鎖定:
#建立鎖 mutex = threading.Lock() #鎖定 mutex.acquire([blocking]) #釋放 mutex.release()
其中,鎖定⽅法acquire能夠有⼀個blocking參數。
·若是設定blocking爲True,則當前線程會堵塞,直到獲取到這個鎖爲⽌
(若是沒有指定,那麼默認爲True)
·若是設定blocking爲False,則當前線程不會堵塞
from threading import Thread, Lock import time g_num = 0 def test1(): global g_num for i in range(1000000): #True表示堵塞 即若是這個鎖在上鎖以前已經被上鎖了,那麼這個線程會在這⾥⼀直等待到解鎖爲⽌ #False表示⾮堵塞,即無論本次調⽤可以成功上鎖,都不會卡在這,⽽是繼續執⾏下⾯的代碼 mutexFlag = mutex.acquire(True) if mutexFlag: g_num += 1 mutex.release() print("---test1---g_num=%d"%g_num) def test2(): global g_num for i in range(1000000): mutexFlag = mutex.acquire(True) #True表示堵塞 if mutexFlag: g_num += 1 mutex.release() print("---test2---g_num=%d"%g_num) #建立⼀個互斥鎖 #這個所默認是未上鎖的狀態 mutex = Lock() p1 = Thread(target=test1) p1.start() p2 = Thread(target=test2) p2.start() print("---g_num=%d---"%g_num)
11.同步應用--多個線程有序執⾏
from threading import Thread,Lock from time import sleep class Task1(Thread): def run(self): while True: if lock1.acquire(): print("------Task 1 -----") sleep(0.5) lock2.release() class Task2(Thread): def run(self): while True: if lock2.acquire(): print("------Task 2 -----") sleep(0.5) lock3.release() class Task3(Thread): def run(self): while True: if lock3.acquire(): print("------Task 3 -----") sleep(0.5) lock1.release() #使⽤Lock建立出的鎖默認沒有「鎖上」 lock1 = Lock() #建立另外⼀把鎖,而且「鎖上」 lock2 = Lock() lock2.acquire() #建立另外⼀把鎖,而且「鎖上」 lock3 = Lock() lock3.acquire() t1 = Task1() t2 = Task2() t3 = Task3() t1.start() t2.start() t3.start()
12.⽣產者與消費者模式
隊列:先進先出
棧:先進後出
⽣產者與消費者模式能夠用來解決寫入,讀取不一樣步問題
⽣產者消費者模式是經過⼀個容器來解決⽣產者和消費者的強耦合問題。⽣
產者和消費者彼此之間不直接通信,⽽經過阻塞隊列來進⾏通信,因此⽣產
者⽣產完數據以後不⽤等待消費者處理,直接扔給阻塞隊列,消費者不找⽣
產者要數據,⽽是直接從阻塞隊列⾥取,阻塞隊列就至關於⼀個緩衝區,平
衡了⽣產者和消費者的處理能⼒。
這個阻塞隊列就是⽤來給⽣產者和消費者解耦的。縱觀⼤多數設計模式,都
會找⼀個第三者出來進⾏解耦,
13.ThreadLocal
ThreadLocal應運⽽⽣,不⽤查找dict,ThreadLocal幫你⾃動作這件事:
import threading # 建立全局ThreadLocal對象: local_school = threading.local() def process_student(): # 獲取當前線程關聯的student: std = local_school.student print('Hello, %s (in %s)' % (std, threading.current_thread().name)) def process_thread(name): # 綁定ThreadLocal的student: local_school.student = name process_student() t1 = threading.Thread(target= process_thread, args=('dongGe',), name= t2 = threading.Thread(target= process_thread, args=('⽼王',), name= t1.start() t2.start() t1.join() t2.join()
說明 全局變量local_school就是⼀個ThreadLocal對象,每一個Thread對它均可以讀 寫student屬性,但互不影響。你能夠把local_school當作全局變量,但每一個 屬性如local_school.student都是線程的局部變量,能夠任意讀寫⽽互不⼲ 擾,也不⽤管理鎖的問題,ThreadLocal內部會處理。 能夠理解爲全局變量local_school是⼀個dict,不但能夠⽤ local_school.student,還能夠綁定其餘變量,如local_school.teacher等等。 ThreadLocal最常⽤的地⽅就是爲每一個線程綁定⼀個數據庫鏈接,HTTP請 求,⽤戶身份信息等,這樣⼀個線程的全部調⽤到的處理函數均可以⾮常⽅ 便地訪問這些資源。