day9線程和進程

進程:qq要以一個總體的形式暴露給操做系統管理,裏面包含對各類資源的調用,內存的對各類資源管理的集合,就可稱之爲進程。python

線程:是操做系統最小的調度單位,是一串指令的集合。編程

進程:要操做CPU,必需要先建立一個線程,進程不能單獨執行,進程執行是調動線程,至少要有一個線程;安全

進程是資源的集合,線程是最小的單位,全部速度沒有可比性。啓動線程快。多線程

線程共享內存空間,進程的內存是相互獨立的。併發

同一個進程的線程之間能夠直接交流,兩個進程想通訊,必須經過一箇中間代理來實現。app

建立新線程很簡單,建立新進程須要對其父進程進行一次克隆。dom

一個線程能夠控制和操做同一進程裏的其餘線程,可是進程只能操做子進程。函數

使用函數定義一個線程:ui

 

 
 
import threading,time

def func(num):
print("Runing on %s threading......" %num)
time.sleep(2)

if __name__ == "__main__":
start_time = time.time()
t1 = threading.Thread(target=func,args=(1,)) #生成一個線程t1實例
t2 = threading.Thread(target=func,args=(2,))

t1.start() #啓動線程t1
t2.start()

print(t1.getName()) #獲取線程名
print(t2.getName())

end_time = time.time()
spend_time = end_time - start_time
print("花費時間:",spend_time)

 

    上面代碼,生成了一個線程,線程同時執行,若是正常狀況下,確定先執行t1,而後執行t2,花費的時間是4秒以上,可是使用線程,執行之間只有兩秒多,以下:spa

Runing on 1 threading......
Thread-1
Thread-2
花費時間: 0.0005929470062255859
Runing on 2 threading......

    因爲上述代碼是並行的,線程先執行,執行完成以後等待兩秒。

使用類建立線程:

import threading,time

class MyThreading(threading.Thread):
    '''本身建立的類,繼承的是線程的類,覆蓋了以前的類,所以要重寫父類'''
    def __init__(self,num):
        super(MyThreading,self).__init__()   #括號裏面是加入參數的
        '''重寫父類'''
        self.num = num

    def run(self):   #定義每一個函數運行的函數,類的全部方法在run中,調用run,必須是run函數
        print("Running task %s" %self.num)
        time.sleep(2)


if __name__ == "__main__":
    t3 = MyThreading(1)   #定義線程1
    t4 = MyThreading(2)

    t3.start()            #執行線程1
    t4.start()

    print(t3.getName())   #獲取線程1的名字
    print(t4.getName())

    上面代碼,是運用類建立的線程,super(MyThreading,self).__init__(),重寫類,生成新的類,使用類建立線程,全部的方法必須定義在run()函數中。

    舊式類啓用線程:

 
 
import threading,time

class MyThread(threading.Thread):
'''用舊式類生成線程'''
def __init__(self,num):
threading.Thread.__init__(self)
self.num = num

def run(self):
print("Start the %s threading......" %self.num)
time.sleep(2)


if __name__ == "__main__":
start_time = time.time() #程序執行起始時間
t5 = MyThread(1) #生成線程1實例
t6 = MyThread(2)

t5.start() #啓動線程1
t6.start()

print(t5.getName()) #獲取線程1名字
print(t6.getName()) #獲取線程2名字

end_time = time.time() #程序執行結束時間
spend_time = end_time - start_time #程序執行花費時間
print(spend_time)
代碼運行結果以下:
Start the 1 threading......
Start the 2 threading......
Thread-1
Thread-2
0.0004968643188476562

    上面使用舊式類寫的類,啓動線程。

    上面的花費時間,是啓用線程的時間,並非程序執行的時間。上面的代碼是並行運行的。

把線程編程串行執行,即一個線程執行完畢再繼續執行下一個線程,以下:

import threading,time

class MyThread(threading.Thread):
    '''用舊式類生成線程'''
    def __init__(self,num):
        threading.Thread.__init__(self)
        self.num = num

    def run(self):
        print("Start the %s threading......" %self.num)
        time.sleep(2)


if __name__ == "__main__":
    start_time = time.time()  # 程序執行起始時間
    for i in range(5):
        t8 = MyThread(i)           #生成線程1實例
        t8.start()
        t8.join()                 #等待線程執行結果,這個線程沒有執行完畢,程序不執行下一步,讓線程執行變成並行

    end_time = time.time()     #程序執行結束時間
    spend_time = end_time - start_time   #程序執行花費時間
    print("--------all theads has finished----------------")
    print(spend_time)
運行結果以下:
Start the 0 threading......
Start the 1 threading......
Start the 2 threading......
Start the 3 threading......
Start the 4 threading......
--------all theads has finished----------------
10.011518001556396

    從結果能夠看出,上面程序執行編程了串行,等待上一個線程執行完畢以後,纔會執行下一個線程,只是在裏面加入一個執行,t1.join(),用來讓程序等待。

    下面咱們讓兩個線程等待執行的時間不必定,以下:

 
 
import threading,time

class MyThread(threading.Thread):
'''用舊式類生成線程'''
def __init__(self,num,execute_time):
threading.Thread.__init__(self)
self.num = num
self.execute_time = execute_time

def run(self):
print("Start the %s threading......" %self.num)
time.sleep(self.execute_time)
print("Threading %s task done!" %self.num)


if __name__ == "__main__":
start_time = time.time() # 程序執行起始時間
t1 = MyThread(1,2) #生成線程1實例
t2 = MyThread(2,4)
t1.start() #執行t1
t2.start() #執行t2
t1.join() #等待線程執行結果,這個線程沒有執行完畢,程序不執行下一步,讓線程執行變成並行

end_time = time.time() #程序執行結束時間
spend_time = end_time - start_time #程序執行花費時間
print("--------all theads has finished----------------")
print(spend_time)

程序執行以下:
Start the 1 threading......
Start the 2 threading......
Threading 1 task done!
--------all theads has finished----------------
2.0026450157165527
Threading 2 task done!

    上面程序中,線程t1和t2同時執行,可是t1.join()只等待第一個線程執行完畢,不會等待第二個線程執行完畢再往下執行,能夠看出,程序向下執行完畢以後,t2還在等待執行過程當中。

    主線程問題,程序運行是有一個主線程在運行的。下面看一個實例:

import threading,time

class MyThread(threading.Thread):
    '''用舊式類生成線程'''
    def __init__(self,num):
        threading.Thread.__init__(self)
        self.num = num

    def run(self):
        print("Start the %s threading......" %self.num)
        time.sleep(4)
        print("Threaing %s task done!!!!" %self.num)


if __name__ == "__main__":
    start_time = time.time()  # 程序執行起始時間
    t_objs = []    #建立一個臨時列表,先讓線程都啓動
    for i in range(50):
        t8 = MyThread(i)           #生成線程1實例
        t8.start()
        t_objs.append(t8)          #啓動全部線程並添加列表中
        #print(t_objs)
    print("當前活躍的線程個數:",threading.active_count())
    for t in t_objs:
        t8.join()                 #全部線程啓動執行完畢以後,等待全部線程執行完畢以後執行下一個線程

    end_time = time.time()     #程序執行結束時間
    print("--------all theads has finished----------------",threading.current_thread(),threading.active_count())
    spend_time = end_time - start_time   #程序執行花費時間
    print(spend_time)
運行結果以下:
Start the 0 threading......
Start the 1 threading......
Start the 2 threading......
Start the 3 threading......
Start the 4 threading......
Start the 5 threading......
Start the 6 threading......
Start the 7 threading......
Start the 8 threading......
Start the 9 threading......
Start the 10 threading......
Start the 11 threading......
Start the 12 threading......
Start the 13 threading......
Start the 14 threading......
Start the 15 threading......
Start the 16 threading......
Start the 17 threading......
Start the 18 threading......
Start the 19 threading......
Start the 20 threading......
Start the 21 threading......
Start the 22 threading......
Start the 23 threading......
Start the 24 threading......
Start the 25 threading......
Start the 26 threading......
Start the 27 threading......
Start the 28 threading......
Start the 29 threading......
Start the 30 threading......
Start the 31 threading......
Start the 32 threading......
Start the 33 threading......
Start the 34 threading......
Start the 35 threading......
Start the 36 threading......
Start the 37 threading......
Start the 38 threading......
Start the 39 threading......
Start the 40 threading......
Start the 41 threading......
Start the 42 threading......
Start the 43 threading......
Start the 44 threading......
Start the 45 threading......
Start the 46 threading......
Start the 47 threading......
Start the 48 threading......
當前活躍的線程個數: 51
Start the 49 threading......
Threaing 1 task done!!!!
Threaing 6 task done!!!!
Threaing 4 task done!!!!
Threaing 3 task done!!!!
Threaing 2 task done!!!!
Threaing 5 task done!!!!
Threaing 0 task done!!!!
Threaing 9 task done!!!!
Threaing 10 task done!!!!
Threaing 11 task done!!!!
Threaing 7 task done!!!!
Threaing 8 task done!!!!
Threaing 13 task done!!!!
Threaing 12 task done!!!!
Threaing 18 task done!!!!
Threaing 39 task done!!!!
Threaing 15 task done!!!!
Threaing 20 task done!!!!
Threaing 24 task done!!!!
Threaing 26 task done!!!!
Threaing 28 task done!!!!
Threaing 35 task done!!!!
Threaing 22 task done!!!!
Threaing 34 task done!!!!
Threaing 42 task done!!!!
Threaing 21 task done!!!!
Threaing 19 task done!!!!
Threaing 25 task done!!!!
Threaing 27 task done!!!!
Threaing 36 task done!!!!
Threaing 38 task done!!!!
Threaing 43 task done!!!!
Threaing 17 task done!!!!
Threaing 14 task done!!!!
Threaing 33 task done!!!!
Threaing 30 task done!!!!
Threaing 40 task done!!!!
Threaing 44 task done!!!!
Threaing 29 task done!!!!
Threaing 41 task done!!!!
Threaing 16 task done!!!!
Threaing 23 task done!!!!
Threaing 31 task done!!!!
Threaing 32 task done!!!!
Threaing 37 task done!!!!
Threaing 47 task done!!!!
Threaing 46 task done!!!!
Threaing 45 task done!!!!
Threaing 48 task done!!!!
Threaing 49 task done!!!!
--------all theads has finished---------------- <_MainThread(MainThread, started 139803255105280)> 1
4.0112504959106445

    上面程序中,咱們啓動了50個線程,可是能夠看出,實際上是由51個線程在執行,其中一個是線程自己,做爲主線程,線程執行完畢以後,只剩下主線程,其餘線程都被殺死,要先實現並行執行線程,全部線程同時啓動,並等待上一個線程執行完畢,接着執行下一個線程,要藉助列表,先生成一個空的列表,把全部生成的線程添加到列表中,而後再遍歷列表,依次執行啓動的線程。

    join()等待全部的線程執行完畢,主線程才繼續執行。

    設置守護線程:

    正常狀況下小,若是沒有設置join(),程序會一直執行,不會管線程是否執行完畢,可是在主線程執行完畢以後,仍是會等待其餘線程執行完畢,以下:

import threading,time

class MyThread(threading.Thread):
    '''用舊式類生成線程'''
    def __init__(self,num):
        threading.Thread.__init__(self)
        self.num = num

    def run(self):
        print("Start the %s threading......" %self.num)
        time.sleep(4)
        print("Threaing %s task done!!!!" %self.num)


if __name__ == "__main__":
    start_time = time.time()  # 程序執行起始時間
    t_objs = []    #建立一個臨時列表,先讓線程都啓動
    for i in range(5):
        t8 = MyThread(i)           #生成線程1實例
        # t8.setDaemon(True)         #把當前線程設置爲守護線程  ,必須在start以前
        '''程序會等待主線程執行完畢,守護線程執行完畢與否是無論的'''
        t8.start()
        t_objs.append(t8)          #啓動全部線程並添加列表中
        #print(t_objs)
    print("當前活躍的線程個數:",threading.active_count())
    # for t in t_objs:
    #     t8.join()                 #全部線程啓動執行完畢以後,等待全部線程執行完畢以後執行下一個線程

    end_time = time.time()     #程序執行結束時間
    print("--------all theads has finished----------------",threading.current_thread(),threading.active_count())
    spend_time = end_time - start_time   #程序執行花費時間
    print(spend_time)
運行結果以下:
Start the 0 threading......
Start the 1 threading......
Start the 2 threading......
Start the 3 threading......
Start the 4 threading......
當前活躍的線程個數: 6
--------all theads has finished---------------- <_MainThread(MainThread, started 139642438694656)> 6
0.0012087821960449219
Threaing 1 task done!!!!
Threaing 4 task done!!!!
Threaing 2 task done!!!!
Threaing 0 task done!!!!
Threaing 3 task done!!!

    從上面代碼運行結果能夠看出,主線程執行完畢以後,又執行了其餘線程,程序在執行過程當中,啓動了線程,可是不會在乎線程是否執行完畢,沒有執行完畢就繼續執行,可是最後會等待其餘線程執行完畢以後結束程序。如何讓主線程執行完畢以後,不等待其餘線程是否執行完畢就結束線程呢?這裏就要用到守護線程了,以下:

import threading,time

class MyThread(threading.Thread):
    '''用舊式類生成線程'''
    def __init__(self,num):
        threading.Thread.__init__(self)
        self.num = num

    def run(self):
        print("Start the %s threading......" %self.num)
        time.sleep(4)
        print("Threaing %s task done!!!!" %self.num)


if __name__ == "__main__":
    start_time = time.time()  # 程序執行起始時間
    t_objs = []    #建立一個臨時列表,先讓線程都啓動
    for i in range(5):
        t8 = MyThread(i)           #生成線程1實例
        t8.setDaemon(True)         #把當前線程設置爲守護線程  ,必須在start以前
        '''程序會等待主線程執行完畢,守護線程執行完畢與否是無論的'''
        t8.start()
        t_objs.append(t8)          #啓動全部線程並添加列表中
        #print(t_objs)
    print("當前活躍的線程個數:",threading.active_count())
    # for t in t_objs:
    #     t8.join()                 #全部線程啓動執行完畢以後,等待全部線程執行完畢以後執行下一個線程

    end_time = time.time()     #程序執行結束時間
    print("--------all theads has finished----------------",threading.current_thread(),threading.active_count())
    spend_time = end_time - start_time   #程序執行花費時間
    print(spend_time)
運行結果以下:
Start the 0 threading......
Start the 1 threading......
Start the 2 threading......
Start the 3 threading......
Start the 4 threading......
當前活躍的線程個數: 6
--------all theads has finished---------------- <_MainThread(MainThread, started 140133686212352)> 6
0.0010912418365478516

    上面程序把全部其餘線程都設置成爲了守護線程,t8.setDaemon(),設置守護線程,設置守護線程必須在start()線程開始以前設置,設置完畢以後,從結果能夠看出,主線程執行完畢以後,就結束了程序,不會管其餘線程是否執行完畢。

    全局解釋器鎖

    Python GIL(Global Interpreter Lock)

    In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)

    上面的核心意思就是,不管你啓多少個線程,你有多少個cpu, Python在執行的時候會淡定的在同一時刻只容許一個線程運行,擦。。。,那這還叫什麼多線程呀?莫如此早的下結結論,聽我現場講。  

    首先須要明確的一點是GIL並非Python的特性,它是在實現Python解析器(CPython)時所引入的一個概念。就比如C++是一套語言(語法)標準,可是能夠用不一樣的編譯器來編譯成可執行代碼。有名的編譯器例如GCC,INTEL C++,Visual C++等。Python也同樣,一樣一段代碼能夠經過CPython,PyPy,Psyco等不一樣的Python執行環境來執行。像其中的JPython就沒有GIL。然而由於CPython是大部分環境下默認的Python執行環境。因此在不少人的概念裏CPython就是Python,也就想固然的把GIL歸結爲Python語言的缺陷。因此這裏要先明確一點:GIL並非Python的特性,Python徹底能夠不依賴於GIL。

    python的線程是調用操做系統的原生線程,Python調用C語言的原生接口。

  線程鎖(互斥鎖Mutex)   

    一個進程下能夠啓動多個線程,多個線程共享父進程的內存空間,也就意味着每一個線程能夠訪問同一份數據,此時,若是2個線程同時要修改同一份數據,會出現什麼情況?

import time
import threading


def addNum():
    global num  # 在每一個線程中都獲取這個全局變量
    print('--get num:', num)
    time.sleep(1)
    num += 1  # 對此公共變量進行-1操做


num = 0  # 設定一個共享變量
thread_list = []
for i in range(50):
    t = threading.Thread(target=addNum)
    t.start()
    thread_list.append(t)
time.sleep(1.000001)

# for t in thread_list:  # 等待全部線程執行完畢
#     t.join()

print('final num:', num)
運行程序以下:
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
--get num: 0
final num: 49

    上面代碼,執行結果有時候是50,有時候是49,如何解決呢?

    用戶加鎖,用戶加鎖確保同一時間只有一個線程在修改數據,上面的代碼,若是在規定時間內,沒有執行完畢,那麼將釋放GIL,讓其餘線程執行,形成過多修改同一數據,所以要用戶本身加鎖,確保同一時間只有一個線程修改數據。

import time
import threading


def addNum():
    global num  # 在每一個線程中都獲取這個全局變量
    print('--get num:', num)

    lock.acquire()    #獲取一把鎖
    time.sleep(1)     #在所裏面sleep()會把程序編程串行
    num += 1  # 對此公共變量進行-1操做
    lock.release()

num = 0  # 設定一個共享變量
thread_list = []
lock = threading.Lock()
for i in range(10):
    t = threading.Thread(target=addNum)
    t.start()
    thread_list.append(t)

for t in thread_list:  # 等待全部線程執行完畢
    t.join()

print('final num:', num)

    加鎖,首先聲明一把鎖,lock=threading.Thread(target=addNum),生成一把鎖,而後在函數中加鎖,lock.acquire(),加鎖,lock.release(),最後釋放鎖,把加的鎖進行釋放,爲何要加鎖呢?由於線程執行的時候,是有實現限制的,在規定時間若是爲執行完畢,GIF會釋放,加鎖是爲了讓在同一時間內,只有同一個線程執行程序。

    加鎖版本

import time
import threading


def addNum():
    global num  # 在每一個線程中都獲取這個全局變量
    print('--get num:', num)
    time.sleep(1)
    lock.acquire()  # 修改數據前加鎖
    num -= 1  # 對此公共變量進行-1操做
    lock.release()  # 修改後釋放


num = 100  # 設定一個共享變量
thread_list = []
lock = threading.Lock()  # 生成全局鎖
for i in range(100):
    t = threading.Thread(target=addNum)
    t.start()
    thread_list.append(t)

for t in thread_list:  # 等待全部線程執行完畢
    t.join()

print('final num:', num)

    遞歸鎖(嵌套鎖)----RLock(遞歸鎖)

    說白了就是在一個大鎖中還要再包含子鎖   

    下面來看一個實例:

import threading, time


def run1():
    print("grab the first part data")
    lock.acquire()
    global num
    num += 1
    lock.release()
    return num


def run2():
    print("grab the second part data")
    lock.acquire()
    global num2
    num2 += 1
    lock.release()
    return num2


def run3():
    lock.acquire()    #第一道鎖加鎖,首先進入此鎖
    res = run1()      #進入第二道鎖,第二道也有鎖
    print('--------between run1 and run2-----')
    res2 = run2()     #平行進入第二道鎖,和上面run1是並行鎖
    lock.release()
    print(res, res2)


if __name__ == '__main__':

    num, num2 = 0, 0
    lock = threading.Lock()
    for i in range(10):
        t = threading.Thread(target=run3)
        t.start()

while threading.active_count() != 1:
    print(threading.active_count())
else:
    print('----all threads done---')
    print(num, num2)

    上面代碼是一把大鎖裏面嵌套一把小鎖,這樣會形成什麼問題呢?以下:

11
11
11
11
11
11
......

    上面代碼執行陷入了一個死循環,程序不停的執行,爲何呢?

    遞歸鎖--RLock:防止鎖死

import threading, time


def run1():
    print("grab the first part data")
    lock.acquire()
    global num
    num += 1
    lock.release()
    return num


def run2():
    print("grab the second part data")
    lock.acquire()
    global num2
    num2 += 1
    lock.release()
    return num2


def run3():
    lock.acquire()    #第一道鎖加鎖,首先進入此鎖
    res = run1()      #進入第二道鎖,第二道也有鎖
    print('--------between run1 and run2-----')
    res2 = run2()     #平行進入第二道鎖,和上面run1是並行鎖
    lock.release()
    print(res, res2)


if __name__ == '__main__':

    num, num2 = 0, 0
    lock = threading.RLock()
    for i in range(10):
        t = threading.Thread(target=run3)
        t.start()

while threading.active_count() != 1:
    print(threading.active_count())
else:
    print('----all threads done---')
    print(num, num2)
運行結果以下:
grab the first part data
--------between run1 and run2-----
grab the second part data
1 1
grab the first part data
--------between run1 and run2-----
grab the second part data
2 2
grab the first part data
--------between run1 and run2-----
grab the second part data
3 3
grab the first part data
--------between run1 and run2-----
grab the second part data
4 4
grab the first part data
--------between run1 and run2-----
grab the second part data
5 5
grab the first part data
--------between run1 and run2-----
grab the second part data
6 6
grab the first part data
--------between run1 and run2-----
grab the second part data
7 7
grab the first part data
--------between run1 and run2-----
grab the second part data
8 8
grab the first part data
--------between run1 and run2-----
grab the second part data
9 9
grab the first part data
2
--------between run1 and run2-----
grab the second part data
10 10
----all threads done---
10 10

    從上面代碼能夠看出,使用RLokc()遞歸所可以正確的執行退出。因此加鎖屢次的時候,爲了防止鎖死,應該使用遞歸鎖。

  Semaphore(信號量)

    互斥鎖 同時只容許一個線程更改數據,而Semaphore是同時容許必定數量的線程更改數據 ,好比廁全部3個坑,那最多隻容許3我的上廁所,後面的人只能等裏面有人出來了才能再進去。

    Semaphore(信號量)同一時間只容許必定數量的線程更改數據。

import threading, time


def run(n):
    semaphore.acquire()
    time.sleep(1)
    print("run the thread: %s\n" % n)
    semaphore.release()


if __name__ == '__main__':

    semaphore = threading.BoundedSemaphore(5)  # 最多容許5個線程同時運行
    '''每出來一個就會補充一個進去,限制線程裏面只有必定數量的線程在執行,確保同一時間只有五個併發執行'''
    for i in range(17):
        t = threading.Thread(target=run, args=(i,))
        t.start()

while threading.active_count() != 1:
    pass  # print threading.active_count()
else:
    print('----all threads done---')
運行結果以下:
run the thread: 0
run the thread: 3
run the thread: 4

run the thread: 1

run the thread: 2



run the thread: 7
run the thread: 8

run the thread: 6

run the thread: 5


run the thread: 9

run the thread: 10
run the thread: 14

run the thread: 11

run the thread: 12
run the thread: 13



run the thread: 16
run the thread: 15


----all threads done---

    上面代碼中,限定了同一時間執行的線程個數,semaphore=threading.BoundedSemaphore(5)規定同一時間只有5個線程在執行,當裏面有線程執行完畢以後,就會有新的線程補充進來,知道全部線程都執行完畢。

    Events(事件)

    事件:狀態的切換,每一次狀態的切換會致使其餘的變化,如紅綠燈。

    時間:是一個很是簡單的事件同步對象;一個事件須要一個內部標誌。

    event = threading.Event()    #聲明一個event()對象

    event.set()                  #設置一個全局變量,即標誌位

    event.clear()                #清空標誌位

    event.set()至關於True,event.clear()至關於False。

    event.wait()檢測標誌位是否設置,若是沒有設置,會一直卡在哪裏,不往下走。若是標誌位設置則不會堵塞,wait()等待標誌位被設置。

    If the flag is set, the wait method doesn’t do anything.

    標誌位設定了,表明綠燈,直接通行。
  If the flag is cleared, wait will block until it becomes set again.

    標誌位被清空,表明紅燈,wait()等待變路燈。
  Any number of threads may wait for the same event.

    每一個線程均可以等待同一個事件。

    下面來寫一個紅綠燈的事件:

  經過Event來實現兩個或多個線程間的交互,下面是一個紅綠燈的例子,即起動一個線程作交通指揮燈,生成幾個線程作車輛,車輛行駛按紅燈停,綠燈行的規則。

import threading,time
import random
def light():
    if not event.isSet():
        event.set() #wait就不阻塞 #綠燈狀態
    count = 0
    while True:
        if count < 10:
            print('\033[42;1m--green light on---\033[0m')
        elif count <13:
            print('\033[43;1m--yellow light on---\033[0m')
        elif count <20:
            if event.isSet():
                event.clear()
            print('\033[41;1m--red light on---\033[0m')
        else:
            count = 0
            event.set() #打開綠燈
        time.sleep(1)
        count +=1
def car(n):
    while 1:
        time.sleep(random.randrange(10))
        if  event.isSet(): #綠燈
            print("car [%s] is running.." % n)
        else:
            print("car [%s] is waiting for the red light.." %n)
if __name__ == '__main__':
    event = threading.Event()
    Light = threading.Thread(target=light)
    Light.start()
    for i in range(3):
        t = threading.Thread(target=car,args=(i,))
        t.start()

    紅綠燈:

import threading,time

event = threading.Event()   #聲明一個event事件對象

def lighter():
    count = 0
    event.set()
    while True:
        if count > 20 and count < 30:    #改爲紅燈
            event.clear()     #把標誌位清空
            print("\033[41;1mred light is on.......\033[0m")
        elif count > 30:
            event.set()       #設置標誌位,變綠燈

            count = 0     #變成綠燈以後從新計數
        else:
            print("\033[42;1mgreen linght in on ......\033[0m")

        time.sleep(1)
        count += 1

def car(name):
    while True:    #檢測標誌位,存在則是綠燈,通行
        if event.is_set():     #若是設置了標誌位,表明綠燈
            print("[%s] running ....." %name)
            time.sleep(1)
        else:
            print("[%s] sees red light,waiting please......." %name)
            event.wait()     #等待,標誌位不存在,則等待標誌位從新設定
            print("\033[34;1m[%s] green light in on ,start going ......\033[0m" %name)

light = threading.Thread(target=lighter)
light.start()

car1 = threading.Thread(target=car,args=("tesla",))
car1.start()

    上面代碼就是實現了一個紅綠燈的程序,程序運行結果以下:

green linght in on ......
[tesla] running .....
green linght in on ......
[tesla] running .....
green linght in on ......
[tesla] running .....
green linght in on ......
[tesla] running .....
[tesla] running .....
green linght in on ......
green linght in on ......
[tesla] running .....
[tesla] running .....
green linght in on ......
green linght in on ......
[tesla] running .....
green linght in on ......
[tesla] running .....
green linght in on ......
[tesla] running .....
green linght in on ......
[tesla] running .....
green linght in on ......
[tesla] running .....
green linght in on ......
[tesla] running .....
[tesla] running .....
green linght in on ......
[tesla] running .....
green linght in on ......
[tesla] running .....
green linght in on ......
[tesla] running .....
green linght in on ......
green linght in on ......
[tesla] running .....
green linght in on ......
[tesla] running .....
green linght in on ......
[tesla] running .....
green linght in on ......
[tesla] running .....
red light is on.......
[tesla] sees red light,waiting please.......
red light is on.......
red light is on.......
red light is on.......
red light is on.......
red light is on.......
red light is on.......
red light is on.......
red light is on.......
green linght in on ......
[tesla] green light in on ,start going ......
[tesla] running .....
green linght in on ......

    上面程序,實現了簡單的紅綠燈交替狀況。

    queue隊列  

 

    Python中,隊列是線程間最經常使用的交換數據的形式。Queue模塊是提供隊列操做的模塊,雖然簡單易用,可是不當心的話,仍是會出現一些意外。

    queue是實現線程間信息的安全交換。

    建立一個「隊列」對象
  import Queue
  q = Queue.Queue(maxsize = 10)
  Queue.Queue類便是一個隊列的同步實現。隊列長度可爲無限或者有限。可經過Queue的構造函數的可選參數maxsize來設定隊列長度。若是maxsize小於1就表示隊列長度無限。 

  隊列能夠設置長度,maxsize=n,設置最大元素個數,使用put()添加數據,當超過maxsize以後,會形成卡頓。以下:

import queue

q = queue.Queue(maxsize=4)
q.put("alex")
q.put("wupeiqi")
q.put("sfasfd")
q.put("sb")
q.put("sdfasfd")
print(q.qsize())

    上面代碼中,定義了隊列的大小,只能放入4個元素,當咱們放過多的時候,形成卡頓。

import queue

q = queue.Queue(maxsize=4)
q.put("alex")
q.put("wupeiqi")
q.put("sfasfd")
q.put("sb")
print(q.qsize())

q.get()
q.get()
q.get()
q.get()

    使用get()獲取數據,若是get()超過限制,就會形成卡頓,由於實在等待數據的存放,隊列一直是在等待數據的存取。

    隊列的集中方式:

  queue.Queue(maxsize)                #先入先出

    queue.LifoQueue(maxsize)            #last in first out後進先出

    queue.PriorityQueue(maxsize=0)      #存儲數據可設置優先級的隊列。   

    隊列中的方法:

    q.get_nowait()若是沒有數據取,會報一個異常。

    q.qsize()判斷隊列的長度。

    q.qsize()

    q.empty()   #判斷隊列是不是空的

  q.full()   #判斷隊列是否存放滿了

  q.put(item,block=True,timeout=None)   block=True當queue滿的時候,會卡主,False則會異常;timeout=None設置卡主多久報異常。

    優先級的queue,queue.PriorityQueue(maxsize=0)

 

import queue

q = queue.PriorityQueue()
q.put((10,"alex"))
q.put((-1,"chenronghua"))
q.put((9,"alex"))
q.put((6,"wangsong"))

print(q.get())
print(q.get())
print(q.get())
print(q.get())
運行結果以下:
(-1, 'chenronghua')
(6, 'wangsong')
(9, 'alex')
(10, 'alex')

 

    從上面代碼能夠看出,是按照順序進行了排序,優先級的queue常常在一些會員登記裏面使用,好比銀行的叫號系統,是VIP優先的。

    生產者消費者模型

  在併發編程中使用生產者和消費者模式可以解決絕大多數併發問題。該模式經過平衡生產線程和消費線程的工做能力來提升程序的總體處理數據的速度。

    爲何要使用生產者和消費者模式

 

    在線程世界裏,生產者就是生產數據的線程,消費者就是消費數據的線程。在多線程開發當中,若是生產者處理速度很快,而消費者處理速度很慢,那麼生產者就必須等待消費者處理完,才能繼續生產數據。一樣的道理,若是消費者的處理能力大於生產者,那麼消費者就必須等待生產者。爲了解決這個問題因而引入了生產者和消費者模式。

    什麼是生產者消費者模式

    生產者消費者模式是經過一個容器來解決生產者和消費者的強耦合問題。生產者和消費者彼此之間不直接通信,而經過阻塞隊列來進行通信,因此生產者生產完數據以後不用等待消費者處理,直接扔給阻塞隊列,消費者不找生產者要數據,而是直接從阻塞隊列裏取,阻塞隊列就至關於一個緩衝區,平衡了生產者和消費者的處理能力。

import queue,threading,time

q = queue.Queue(maxsize=10)                              #生成一個隊列實例
def Producer(name):
    count = 1
    while True:
        time.sleep(0.2)
        q.put("骨頭%i" %count)
        print("[%s]生成了[%s]骨頭......"  %(name,count))
        count += 1

def Consumer(name):
    while True :
        time.sleep(1)
        print("[%s] 取到[%s],而且吃了它......" %(name,q.get()))

p = threading.Thread(target=Producer,args=("alex",))
c = threading.Thread(target=Consumer,args=("chenronghua",))
c1 = threading.Thread(target=Consumer,args=("王鬆",))

p.start()
c.start()
c1.start()

    上面代碼實現了生產者和消費者的基本模型。

    代碼運行結果以下:

[alex]生成了[1]骨頭......
[alex]生成了[2]骨頭......
[alex]生成了[3]骨頭......
[alex]生成了[4]骨頭......
[chenronghua] 取到[骨頭1],而且吃了它......
[alex]生成了[5]骨頭......
[王鬆] 取到[骨頭2],而且吃了它......
[alex]生成了[6]骨頭......
[alex]生成了[7]骨頭......
[alex]生成了[8]骨頭......
[alex]生成了[9]骨頭......
[chenronghua] 取到[骨頭3],而且吃了它......
[王鬆] 取到[骨頭4],而且吃了它......
[alex]生成了[10]骨頭......
[alex]生成了[11]骨頭......
[alex]生成了[12]骨頭......
[alex]生成了[13]骨頭......
[alex]生成了[14]骨頭......
[chenronghua] 取到[骨頭5],而且吃了它......
[王鬆] 取到[骨頭6],而且吃了它......
[alex]生成了[15]骨頭......
相關文章
相關標籤/搜索