python學習之路-線程-day08

大綱:
1.初始線程和進程
2.多線程和多進程
3.創建多線程
4.計算多線程耗時和join方法
5.守護線程
6.線程鎖
7.信號量
8.事件
一.初識線程和進程
1.線程概念
線程是程序執行的最小單位。是進程的一個實體。
2.線程特點
a.在同一進程中的各個線程,都可以共享該進程所擁有的資源。由於同一個進程內的線程共享內存和文件,所以線程之間互相通信不必調用內核。
b.在一個進程中的多個線程之間,可以併發執行,同樣,不同進程中的線程也能併發執行
c.程是能獨立運行的基本單位,因而也是獨立調度和分派的基本單位
d.線程中的實體(數據,程序,實體控制塊-TCB)基本上不擁有系統資源,只是有一點必不可少的、能保證獨立運行的資源。
3.進程概念
一個具有一定獨立功能的程序(程序是指令的集合,是靜態的,不能夠單獨的運行)的的一次運動活動。
程序以一個整體的形式暴露給操作系統,裏面包含各種資源的調用,內存的管理,網絡接口的調用,對各種資源管理的集合就是進程
4.進程的特點
a.進程是一個實體
b.進程是一個運行着的程序。是動態的
5.進程和線程之間的區別?
a.線程共享內存空間,而進程的內存是相對獨立的。
b.同一個進程間的線程可以相互交流,但是兩個進程想實現通訊必須要有一箇中間代理
c.創建新線程很簡單,但是創建新的進程是對父進程的再一次的克隆
d.一個線程可以控制和操作同一個進程裏的其他線程,但是一個進程只能操作子進程。
二.多線程和多進程
一個任務就是一個進程,比如說我們打開一個qq聊天就是執行了一個進程,我們可以在打開qq聊天的同時,打開word打字,可以瀏覽網頁,這時我們就是執行了多個進程。在打開word的任務裏面,可以執行編輯,打印等一系列子任務,那麼每一個子任務都是一個線程。python中一個進程至少有一個線程。那麼怎樣實現多任務併發呢?
a.同時執行多個進程
b.同時執行多個線程
c.同時執行多個進程+多個線程
無論你啓多少個線程,你有多少個cpu, Python在執行的時候會淡定的在同一時刻只允許一個線程運行,那麼我們上面說的都是廢話?python怎樣實現多任務併發的呢。操作系統輪流讓各個任務交替執行,任務1執行0.01秒,切換到任務2,任務2執行0.01秒,再切換到任務3,執行0.01秒……這樣反覆執行下去。表面上看,每個任務都是交替執行的,但是,由於CPU的執行速度實在是太快了,我們感覺就像所有任務都在同時執行一樣。
三.創建多線程
兩種方式:
1.直接創建

import  threading,time#創建線程使用模塊threading
def run(n):
    print("task:",n)
    time.sleep(2)
t1=threading.Thread(target=run,args=("t1",))#創建線程t1
t2=threading.Thread(target=run,args=("t2",))#創建線程t2
t1.start()#開啓線程t1
t2.start()
#執行結果t1和t2同時執行完成,是多線程並行
run("t1")
run("t2")
#執行結果,先執行了任務t1,等待了2s後再執行的t2,是多線程串行

2.通過調用的方式創建—面向對象的方法

import threading
class MyThread(threading.Thread):#繼承了threading.Thread
    def __init__(self,n):
        super(MyThread,self).__init__()#繼承
        self.n=n
    def run(self):#start中就調用了run方法執行
        print("task:",self.n)
t1=MyThread("t1")
t2=MyThread("t2")
t1.start()
t2.start()

四.計算多線程運行的時間實例及jion方法的使用

import  threading,time#創建線程使用模塊threading
def run(n):
    print("task:",n)
    time.sleep(2)
    print("每次是什麼進程",threading.current_thread())#子線程
    print("當前活躍線程個數", threading.active_count())#當前活躍線程個數 16
start_time=time.time()
obj_list=[]#建立一個空列表來存放線程
for i in range(15):#利用循環的方式創建15個線程
    t=threading.Thread(target=run,args=("t-%s"%i,))
    t.start()
    obj_list.append(t)#將運行的15個線程依次加入到列表裏面
for t in (obj_list):#循環線程的實例列表,等待所有線程執行完畢
    t.join()#join是什麼意思?
end_time=time.time()
print("cost:",(end_time-start_time))
#執行結果---cost: 2.00500011444
print("查看當前是什麼線程",threading.current_thread())#查看當前是什麼線程 <_MainThread(MainThread, started)>

上面的程序引入了一個join的方法
1.join()
join的作用是保證當前線程執行完成後,再執行其它線程。join可以有timeout參數,表示阻塞其它線程timeout秒後,不再阻塞。

import threading,time
def sayhello(num):
    print("hello world")
    time.sleep(2)
start_time=time.time()
for i in range(3):
    t=threading.Thread(target=sayhello,args=("t-%s"%i,))
    t.start()
    t.join()
print("main process over")
end_time = time.time()
print("cost:",(end_time-start_time))
#加了join程序變成了串行----cost: 6.00499987602
#去掉jion-----cost: 0程序全部執行完成後等待2s退出

五.守護線程
什麼是守護線程?如果設置了守護線程證明這個線程就變得不重要。假如非守護線程執行完畢退出,整個程序就全部退出
,那麼不用等守護線程執行完畢。
怎樣設置守護線程:在t.start()之前設置t.setDaemon(True)就表示這個線程“不重要”。這裏默認是false
下面我們就用具體的代碼驗證一下這個結論

import threading,time
def run():
    print("start run")
    time.sleep(1)
    print("end run")
print("start main")
t=threading.Thread(target=run)
t.start()
print("end main")

執行結果:等待所有進程執行完畢,程序才退出
start main
start run
end main
end run

import threading,time
def run():
    print("start run")
    time.sleep(1)
    print("end run")
print("start main")
t=threading.Thread(target=run)
t.setDaemon(True)
t.start()
print("end main")

執行結果:
start main
end main
start run
六.線程鎖(又叫互斥鎖–mutex)
線程是相互獨立存在的,但是同一個進程下的線程是共享這個進程的同一片資源的,加入發生三個線程同時修改進程的同一份數據就會發生不可預期的結果。這個時候就引入了線程鎖,在執行線程的共享數據池之前先申請一把鎖,保證同一時間只有一個線程修改同一份數據。
不知爲何,在python加鎖和不加鎖執行效果一樣,建議在python2中執行以下程序比較
1.加鎖

import threading,time
num=0
lock=threading.Lock()#創建鎖
def add():
    global num
    lock.acquire()#獲取鎖 鎖定方法acquire可以有一個超時時間的可選參數timeout。如果設定了timeout,
# 則在超時後通過返回值可以判斷是否得到了鎖,從而可以進行一些其他的處理。
    num=num+1
    lock.release()#釋放鎖
obj_list=[]
for i in range(10):
     t=threading.Thread(target=add)
     t.start()
     obj_list.append(t)
for i in obj_list:
     t.join()#等待所有的子線程執行完畢,主線程纔可以向下執行
print("num:",num)

2.不加鎖

import threading,time
num=0
#lock=threading.Lock()#創建鎖
def add():
    global num
    #lock.acquire()#獲取鎖 鎖定方法acquire可以有一個超時時間的可選參數timeout。如果設定了timeout,
# 則在超時後通過返回值可以判斷是否得到了鎖,從而可以進行一些其他的處理。
    num=num+1
    #lock.release()#釋放鎖
obj_list=[]
for i in range(10):
     t=threading.Thread(target=add)
     t.start()
     obj_list.append(t)
for i in obj_list:
     t.join()#等待所有的子線程執行完畢,主線程纔可以向下執行
print("num:",num)

七.線程–信號量(semaphore )
信號量用在多線程多任務同步的,一個線程完成了某一個動作就通過信號量告訴別的線程,別的線程再進行某些動作。互斥鎖同一時間只允許一個線程修改共享數據,但是信號量允許一定數量的線程同時修改數據。

import threading,time
def run(n):
    sema.acquire()#獲取信號量鎖
    time.sleep(2)
    print("run thread:%s"%n)
    sema.release()()#釋放信號量鎖


if __name__=='__main__':
    sema=threading.BoundedSemaphore(5)#創建信號量,最多允許5個進程同時執行
    for i in range(22):
        t=threading.Thread(target=run,args=(i,))
        t.start()

執行結果
這裏寫圖片描述
八.線程–事件
線程的event是爲了實現多個線程間的通訊
enent有三個函數,事件處理的機制:全局定義了一個“Flag”,如果“Flag”值爲 False,那麼當程序執行 event.wait 方法時就會阻塞,如果“Flag”值爲True,那麼event.wait 方法時便不再阻塞。
e=threading.event()
e.wait()等待標誌位被設定,阻塞
e.set()標誌位設定,恢復正常運行
e.clear()標誌位被清空
舉例:紅綠燈

import time,threading
event = threading.Event()
def lighter():
  count=0
  event.set()
  while True:
    if count>=0 and count<10:
        event.set()#設置標誌位,變爲綠燈允許通行
        print("greenlight is on...")
    elif count>=10 and count<20 :
        event.clear()#清空標誌位,變爲紅燈禁止通行
        print("redlight is on...")
    else:
        count=0#重置,進入循環
    time.sleep(5)
    count+=1
light = threading.Thread(target=lighter)
light.start()
def car():
  while True:
    time.sleep(5)
    if event.isSet():
        print("car can run")
    else:
        print("light turn on red ,stop")

car1=threading.Thread(target=car)
car1.start()
發佈了46 篇原創文章 · 獲贊 3 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章