1. 程式人生 > >python之路--關於執行緒的一些方法

python之路--關於執行緒的一些方法

1. 執行緒的兩種建立方式

from threading import Thread
# 第一種建立方式
def f1(n):
    print('%s號執行緒任務'%n)
def f2(n):
    print('%s號執行緒任務'%n)
if __name__ == '__main__':
    t1 = Thread(target=f1,args=(1,))
    t2 = Thread(target=f2,args=(2,))
    t1.start()
    t2.start()
    print('主執行緒')
# 第二種建立方式
class MyThread(Thread):
    def __init__(self,name):
        # super(MyThread, self).__init__()  和下面super是一樣的
        super().__init__()
        self.name = name
    def run(self):
        print('hello girl :' + self.name)
if __name__ == '__main__':
    t = MyThread('alex')
    t.start()
    print('主執行緒結束')

2. 檢視執行緒的pid

import os
from threading import Thread
def f1(n):
    print('1號=>',os.getpid())
    print('%s號執行緒任務' % n)
def f2(n):
    print('2號=>',os.getpid())
    print('%s號執行緒任務' % n)
if __name__ == '__main__':
    t1 = Thread(target=f1,args=(1,))
    t2 = Thread(target=f2,args=(2,))
    t1.start()
    t2.start()
    print('主執行緒', os.getpid())
    print('主執行緒')
    
# 由於這些執行緒都是在一個程序中的,所以pid一致

3.  驗證執行緒之間的資料共享

import time
from threading import Thread
num = 100
def f1(n):
    global num
    num = 3
    time.sleep(1)
    print('子執行緒的num', num)  # 子執行緒的num 3
if __name__ == '__main__':
    thread = Thread(target=f1,args=(1,))
    thread.start()
    thread.join() # 等待thread執行完在執行下面的程式碼
    print('主執行緒的num', num)  # 主執行緒的num 3

4. 多程序與多執行緒的效率對比

import time
from threading import Thread
from multiprocessing import Process
def f1():
    # io密集型
    # time.sleep(1)

    # 計算型:
    n = 10
    for i in range(10000000):
        n = n + i
if __name__ == '__main__':
    #檢視一下20個執行緒執行20個任務的執行時間
    t_s_time = time.time()
    t_list = []
    for i in range(5):
        t = Thread(target=f1,)
        t.start()
        t_list.append(t)
    [tt.join() for tt in t_list]
    t_e_time = time.time()
    t_dif_time = t_e_time - t_s_time
    #檢視一下20個程序執行同樣的任務的執行時間
    p_s_time = time.time()
    p_list = []
    for i in range(5):
        p = Process(target=f1,)
        p.start()
        p_list.append(p)
    [pp.join() for pp in p_list]
    p_e_time = time.time()
    p_dif_time = p_e_time - p_s_time
    # print('多執行緒的IO密集型執行時間:',t_dif_time)  # 1.0017869472503662 還需要減1秒的time.sleep
    # print('多程序的IO密集型執行時間:',p_dif_time)  # 1.2237937450408936  也需要減1秒的time.sleep

    print('多執行緒的計算密集型執行時間:', t_dif_time)  # 3.58754563331604
    print('多程序的計算密集型執行時間:', p_dif_time)  # 2.1555309295654297

  # 從上述程式碼中的執行效率可以看出來,多執行緒在執行IO密集型的程式的時候速度非常快,但是執行計算密集型的程式的時候很慢,所以說python這門語言不適合做大資料. 

5. 互斥鎖,同步鎖

import time
from threading import Lock, Thread
num = 100
def f1(loc):
    # 加鎖
    with loc:
        global num
        tmp = num
        tmp -= 1
        time.sleep(0.001)
        num = tmp
        # 上面的程式碼相當於 num -= 1 
if __name__ == '__main__':
    t_loc = Lock()
    t_list = []
    for i in range(10):
        t = Thread(target=f1,args=(t_loc,))
        t.start()
        t_list.append(t)
    [tt.join() for tt in t_list]
    print('主線的num',num)

6. 死鎖現象

import time
from threading import Thread,Lock,RLock
def f1(locA,locB):
    locA.acquire()
    print('f1>>1號搶到了A鎖')
    time.sleep(1)
    locB.acquire()
    print('f1>>1號搶到了B鎖')
    locB.release()
    locA.release()
def f2(locA,locB):
    locB.acquire()
    print('f2>>2號搶到了B鎖')
    time.sleep(1)
    locA.acquire()
    print('f2>>2號搶到了A鎖')
    locA.release()
    locB.release()
if __name__ == '__main__':
    # locA = locB = Lock()  # 不能這麼寫,這麼寫相當於這兩個是同一把鎖
    locA = Lock()
    locB = Lock()
    t1 = Thread(target=f1,args=(locA,locB))
    t2 = Thread(target=f2,args=(locA,locB))
    t1.start()
    t2.start()
# 上面的程式碼表示f1 先搶到了A鎖,同時f2 搶到了B鎖,一秒後f1想去想B鎖,同時f2想去搶A鎖,
# 由於鎖需要先放開才能繼續搶,導致了死鎖現象

  

7.遞迴鎖

import time
from threading import Thread, Lock, RLock
def f1(locA, locB):
    locA.acquire()
    print('f1>>1號搶到了A鎖')
    time.sleep(1)
    locB.acquire()
    print('f1>>1號搶到了B鎖')
    locB.release()
    locA.release()
def f2(locA, locB):
    locB.acquire()
    print('f2>>2號搶到了B鎖')
    locA.acquire()
    time.sleep(1)
    print('f2>>2號搶到了A鎖')
    locA.release()
    locB.release()
if __name__ == '__main__':
    locA = locB = RLock()  #遞迴鎖,維護一個計數器,acquire一次就加1,release就減1 , acquire等於0的時候才可以搶
    t1 = Thread(target=f1, args=(locA, locB))
    t2 = Thread(target=f2, args=(locA, locB))
    t1.start()
    t2.start()

  # 遞迴鎖解決了死鎖現象,會讓程式碼繼續執行.

8. 守護執行緒

  守護執行緒會等到所有的非守護執行緒執行結束後才結束

import time
from threading import Thread
from multiprocessing import Process

#守護程序:主程序程式碼執行執行結束,守護程序隨之結束

#守護執行緒:守護執行緒會等待所有非守護執行緒執行結束才結束

def f1():
    time.sleep(2)
    print('1號執行緒')
def f2():
    time.sleep(3)
    print('2號執行緒')
if __name__ == '__main__':
    t1 = Thread(target=f1,)
    t2 = Thread(target=f2,)
    # t1.daemon = True  # 1號程序 和 2 號程序都會列印
    t2.daemon = True # 不會列印2號程序
    t1.start()
    t2.start()
    print('主執行緒結束')
    # 與程序對比
    p1 = Process(target=f1, )
    p2 = Process(target=f2, )
    p1.daemon = True  # 只會列印 2號程序
    p2.daemon = True  # 只會列印1號程序
    p1.start()
    p2.start()
    print('主程序結束')

9. GIL鎖的解釋