day9線程和進程

来源:http://www.cnblogs.com/gengcx/archive/2017/09/02/7461023.html
-Advertisement-
Play Games

進程:qq要以一個整體的形式暴露給操作系統管理,裡面包含對各種資源的調用,記憶體的對各種資源管理的集合,就可稱之為進程。 線程:是操作系統最小的調度單位,是一串指令的集合。 進程:要操作CPU,必須要先創建一個線程,進程不能單獨執行,進程執行是調動線程,至少要有一個線程; 進程是資源的集合,線程是最小 ...


進程:qq要以一個整體的形式暴露給操作系統管理,裡面包含對各種資源的調用,記憶體的對各種資源管理的集合,就可稱之為進程。

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

進程:要操作CPU,必須要先創建一個線程,進程不能單獨執行,進程執行是調動線程,至少要有一個線程;

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

線程共用記憶體空間,進程的記憶體是相互獨立的。

同一個進程的線程之間可以直接交流,兩個進程想通信,必須通過一個中間代理來實現。

創建新線程很簡單,創建新進程需要對其父進程進行一次克隆。

一個線程可以控制和操作同一進程里的其他線程,但是進程只能操作子進程。

使用函數定義一個線程:

 


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秒以上,但是使用線程,執行之間只有兩秒多,如下:

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(
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • HDU 2000.ASCII碼排序 Description: 輸入三個字元後,按各字元的ASCII碼從小到大的順序輸出這三個字元。 Input: 輸入數據有多組,每組占一行,有三個字元組成,之間無空格。 Output: 對於每組輸入數據,輸出一行,字元中間用一個空格分開。 SampleInput: ...
  • 前言 大力推薦該教程: "《Create Your own PHP Framework》" Symfony的學習蠻累的,官方文檔雖然很豐富,但是組織方式像參考書而不是指南,一些不錯的指導性文檔常常是是看組件文檔時提到了才偶然發現的,這方面感覺就跟看Laravel和Webpack的官方文檔有差距。同時 ...
  • 請尊重作者勞動成果,轉載請標明原文鏈接:http://www.cnblogs.com/dylan-java/p/7468336.html 上一篇分析了SpringApplication的run方法的一部分,接下來繼續分析剩下的部分 先起個頭,等有時間了再繼續寫 ...
  • 註冊頁面 <body ><h1>註冊頁面</h1><form action="zhucechuli.php" method="post"><div>用戶名:<input type="text" name="uid"/> </div><div>密碼:<input type="text" name="p ...
  • unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, V... ...
  • 今天是畢業入職的第一個周末,一直對多線程併發方面的知識比較感興趣,因為目前我手裡的項目並沒有涉及到併發方面的知識,所以怕以後遺忘,也便於以後複習和使用,所以總結了一下Lock裡面的一些類的方法。具體的代碼實現例子我在這裡就不做說明解釋了,這些方法都比較容易理解和使用,如果實在是忘記的話可以在隨時查閱 ...
  • //RadomAcess的介面for..i的遍歷比for..loop的快,@more see comments for interface RandomAcess import java.util.ArrayList; import java.util.Iterator; import java.u ...
  • 三天不寫代碼就手生! 把測試代碼記錄下來。 註意事項: 1. 三個方法必須一塊使用,不能只寫 System.MonitorWait(Form1, INFINITE); System.MonitorEnter(Form1); //必須 Log('Thread1 Enter'); System.Moni ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...