1、線程
線程被稱為輕量級進程,是最小執行單元,系統調度的單位。線程切換需要的資源一般,效率一般。
2、多線程
在單個程序中同時運行多個線程完成不同的工作,稱為多線程
3、並發:
操作系統同時執行幾個程序,這幾個程序都由一個cpu處理,但在一個時刻點上只有一個程序在cpu上處理
4、並行:
操作系統同時執行2個程序,但是有兩個cpu,每個cpu處理一個程序,叫並行
5、串行:
是指的我們從事某項工作是一個步驟一個步驟去實施
一、多線程
#python3是假的多線程,它不是真真正正的並行,其實就是串行,只不過利用了cpu上下文的切換而已
1 mport threading 2 import time 3 # def test1(): 4 # for i in range(10): 5 # time.sleep(1) #睡1s 6 # print('test1=========>%s' % i) 7 # 8 # 9 # def test2(): 10 # for i in range(10): 11 # time.sleep(1) 12 # print('test2=========>%s' % i) 13 # 14 # t1 = threading.Thread(target=test1) #定義一個線程 target=函數名 15 # t2 = threading.Thread(target=test2) 16 # t1.start() #開啟線程 17 # t2.start() 18 # test1() 19 # test2()
# 多線程是無序的,並發的
因為在啟動一個線程時,線程不會立即執行,而是等待cpu的資源調度。
1 # def test1(n): 2 # time.sleep(1) 3 # print('task', n) 4 # for i in range(10): 5 # t = threading.Thread(target=test1,args=('t-%s' % i,)) #args= 后接輸出結果 末尾必須加 “ , ” 號 6 # t.start()
#計算並發所用的時間
1 2 # import threading 3 # import time 4 # def dest(n): 5 # time.sleep(1) 6 # print('this is running====>%s' %n) 7 # l = [] #定義一個空列表 8 # start = time.time() #開始的時間 9 # for i in range(10): #10個進程 10 # t = threading.Thread(target=dest,args=(i,)) 11 # t.start() 12 # l.append(t) #把線程執行時間加入到列表 13 # for g in l: 14 # g.join() #等待全部線程執行完畢 15 # end = time.time() #執行結束時間 16 # print('time',(end-start)) #執行結束時間 - 開始執行的時間


1 import threading 2 import time 3 def test1(n): 4 time.sleep(1) 5 print('test1====>%s' %n) 6 def test2(n): 7 time.sleep(2) 8 print('test2====>%s' %n) 9 start = time.time() 10 l = [] 11 t1 = threading.Thread(target=test1,args=(1,)) 12 t2 = threading.Thread(target=test2,args=(2,)) 13 t1.start() 14 t2.start() 15 l.append(t1) 16 l.append(t2) 17 for i in l: 18 i.join() 19 end = time.time() 20 print('time',(end - start))


#多線程共享全局變量
1 # g_num = 0 2 # def update(): 3 # global g_num #global聲明全局變量 4 # for i in range(10): 5 # g_num += 1 6 # 7 # def reader(): 8 # global g_num 9 # print(g_num) 10 # 11 # t1 = threading.Thread(target=update) 12 # t2 = threading.Thread(target=reader) 13 # t1.start() 14 # t2.start() 15
二、GIL全局解釋器鎖

只有獲得GIL鎖的線程才能真正在cpu上運行。所以,多線程在python中只能交替執行,即使100個線程跑在100核cpu上,也只能用到1核。
1 2 # import threading 3 # global_num = 0 4 # def test1(): 5 # global global_num #global聲明全局變量 6 # for i in range(1000000): 7 # global_num += 1 8 # print("test1", global_num,threading.current_thread()) 9 # 10 # def test2(): 11 # global global_num 12 # for i in range(1000000): 13 # global_num += 1 14 # print("test2", global_num,threading.current_thread()) 15 # t1 = threading.Thread(target=test1) 16 # t2 = threading.Thread(target=test2) 17 # t1.start() 18 # t2.start() 19 # print(global_num)

結果說明:每次執行結果都不一樣,原因是python從上往下執行,主線程走的快,當主線程走到最后print打印結果的時候,test1 test2的count++還在繼續執行,所以第一行打印出來的是它們在執行count++過程中的某一個值,至於test1和test2的值不是100w和200w,因為cpu沒有足夠的時間去進行count++就釋放鎖提交了
#互斥鎖
以上出現的結果是隨機的,並非我們想要的,所以要加入互斥鎖。
互斥鎖:
常用來防止兩個進程或線程同一時刻訪問相同的共享資源, 如果一個線程鎖定了一個互斥量,在它解除鎖定之前沒有其他線程可以鎖定這個互斥量。
1 import threading 2 import time 3 global_num = 0 4 5 lock = threading.Lock() #互斥鎖 6 7 def test1(): 8 global global_num 9 lock.acquire() 10 for i in range(1000000): 11 global_num += 1 12 lock.release() 13 print("test1", global_num) 14 15 16 def test2(): 17 global global_num 18 lock.acquire() 19 for i in range(1000000): 20 global_num += 1 21 lock.release() 22 print("test2", global_num) 23 24 t1 = threading.Thread(target=test1) 25 t2 = threading.Thread(target=test2) 26 start_time = time.time() 27 28 t1.start() 29 t2.start() 30 t1.join() 31 t2.join() 32 print(global_num)

加上互斥鎖之后,test1線程執行完才釋放鎖提交,讓test2線程拿到共享資源繼續執行,要想結果是200w,就必須是主線程等子線程執行完之后才執行print。
#只要在進行耗時的IO操作的時候,能釋放GIL,所以只要在IO密集型的代碼里,用多線程就很合適