1. 程式人生 > 實用技巧 >併發程式設計(執行緒)——前言理論,開啟執行緒的兩種方式,執行緒物件join方法,同一個程序下的多個執行緒資料共享,執行緒物件及其他方法,守護執行緒,執行緒互斥鎖,GIL全域性直譯器鎖理論

併發程式設計(執行緒)——前言理論,開啟執行緒的兩種方式,執行緒物件join方法,同一個程序下的多個執行緒資料共享,執行緒物件及其他方法,守護執行緒,執行緒互斥鎖,GIL全域性直譯器鎖理論

一、執行緒理論

計算機相當於大工廠,工廠裡有一個個的車間(程序),有很多人(執行緒)幹不同的事
真正幹活的是執行緒--》執行緒是cup排程的最小單位
程序是資源分配的最小單位,執行緒是CPU排程的最小單位。每一個程序中至少有一個執行緒
執行緒開銷更小,更輕量級

二、開啟執行緒的兩種方式

1、函式式

#第一種
from threading import Thread
import time

def task():
    print('開始')
    time.sleep(1)
    print('結束')


if __name__ == '__main__':
    t=Thread(target=task,) #
例項化得到一個物件 t.start() # 物件.start()啟動執行緒 print(''

2、通過類繼承方式

#第二種
from threading import Thread
import time

class MyThread(Thread):
    def run(self):
        print('開始')
        time.sleep(1)
        print('結束')

if __name__ == '__main__':
    t=MyThread()
    t.start()
    print('')

三、執行緒物件join方法

from threading import Thread

import time
def task(n):
    print('開始')
    time.sleep(n)
    print('結束')


if __name__ == '__main__':
    t=Thread(target=task,args=(2,))
    t.start()


    t1=Thread(target=task,args=(3,))
    t1.start()


    t.join()  # 等待子程序執行結束
    t1.join()
    print('')

四、同一個程序下多個執行緒資料共享

from threading import Thread

import time

money = 99


def task(n):
    global money
    money=n
    print('開始')
    # time.sleep(n)
    print('結束')


if __name__ == '__main__':
    t = Thread(target=task, args=(2,))
    t.start()

    t1 = Thread(target=task, args=(66,))
    t1.start()


    t.join()
    t1.join()
    print(money)
    print('')

五、執行緒物件及其他方法

from threading import Thread, current_thread,active_count
import time


def task():
    print('開始')
    print(current_thread().name)   # 執行緒名字
    time.sleep(1)
    print('結束')



if __name__ == '__main__':
    t1 = Thread(target=task,name='egon')
    t2 = Thread(target=task)
    t1.start()
    t2.start()
    print(active_count())  # 打印出3 ,開了兩個執行緒,還有一個主執行緒

from threading import Thread, current_thread,active_count
import time
import os


def task(n):
    print('開始')
    print(current_thread().name)   # 執行緒名字
    # 如果列印程序id號,會是什麼
    print(os.getpid())
    time.sleep(n)
    print('結束')



if __name__ == '__main__':
    t1 = Thread(target=task,name='egon',args=(2,))
    t2 = Thread(target=task,args=(8,))
    t1.start()
    t2.start()
    t1.join()
    print('---------',t1.is_alive())
    print('---------',t2.is_alive())

    # 當作執行緒id號
    print('*********',t1.ident)
    print('*********',t2.ident)

    print(os.getpid())
    print(active_count())  # 打印出3 ,開了兩個執行緒,還有一個主執行緒

總結必知:

1 執行緒t.name  t.getName()
2 當前程序下有幾個執行緒存活active_count
3 t1.is_alive() 當前執行緒是否存活
4 t1.ident  當作是執行緒id號

六、守護執行緒

from threading import Thread, current_thread,active_count
import time
import os


def task(n):
    print('開始')
    time.sleep(n)
    # print('-----',active_count())
    print('結束')



if __name__ == '__main__':
    t1 = Thread(target=task,name='egon',args=(10,))
    # t1.daemon = True
    t1.setDaemon(True)
    t1.start()

    t2 = Thread(target=task,name='egon',args=(4,))
    t2.start()

    print('')

七、執行緒互斥鎖

from threading import Thread,Lock
# from multiprocessing import Lock
import time
import random

money = 99


def task(n,mutex):
    global money
    # 在修改資料的時候,枷鎖
    mutex.acquire()
    temp = money
    time.sleep(0.1)

    money = temp - 1
    # 修改完以後,釋放鎖,其它執行緒就能再次搶到鎖
    mutex.release()


if __name__ == '__main__':
    ll=[]
    mutex=Lock()
    for i in range(10):
        t = Thread(target=task, args=(i,mutex))
        t.start()
        ll.append(t)

    for i in ll:
        i.join()

    print(money)

八、GIL全域性直譯器鎖理論

1 python的直譯器有很多,cpython,jpython,pypy(python寫的直譯器)
2 python的庫多,庫都是基於cpython寫起來的,其他直譯器沒有那麼多的庫
3 cpython中有一個全域性大鎖,每條執行緒要執行,必須獲取到這個鎖
4 為什麼會有這個鎖呢?python的垃圾回收機制
5 python的多執行緒其實就是單執行緒
6 某個執行緒想要執行,必須先拿到GIL,我們可以把GIL看作是“通行證”,並且在一個python程序中,GIL只有一個。拿不到通行證的執行緒,就不允許進入CPU執行

7 總結:cpython直譯器中有一個全域性鎖(GIL),執行緒必須獲取到GIL才能執行,我們開的多執行緒,不管有幾個cpu,同一時刻,只有一個執行緒在執行(python的多執行緒,不能利用多核優勢)

8 如果是io密集型操作:開多執行緒
9如果是計算密集型:開多程序
(8 9 這兩句話,只針對與cpython直譯器)

九、

---38---