并發(fā)編程-線程

一:并發(fā)和并行

并發(fā):指的是任務數(shù)多余cpu核數(shù),通過操作系統(tǒng)的各種任務調(diào)度算法,實現(xiàn)用多個任務“一起”執(zhí)行(實際上總有一些任務不在執(zhí)行,因為切換任務的速度相當快,看上去一起執(zhí)行而已)
并行:指的是任務數(shù)小于等于cpu核數(shù),即任務真的是一起執(zhí)行


image.png

image.png

二:threading模塊

2-1:Thread類

創(chuàng)建線程對象的參數(shù):
    target:指定任務函數(shù)
    name:設(shè)置線程名
    args:給任務函數(shù)傳參
    kwargs:給任務函數(shù)傳參
    daemon:設(shè)置是否作為守護線程

2-2:方法

start:啟動線程執(zhí)行
join:設(shè)置主線程等待子線程執(zhí)行
2-2-1:方法的使用
import time
from threading import Thread
def func1():
    for i in range(5):
        print("------正在做事情1-----")
        time.sleep(1)

def func2():
    for i in range(6):
        print("------正在做事情2-----")
        time.sleep(1)
st = time.time()
#創(chuàng)建一個線程對象
t1 = Thread(target=func1)
t2 = Thread(target = func2)

# 啟動線程執(zhí)行
t1.start()
t2.start()

# 主線程等待t1執(zhí)行完,再往下執(zhí)行
t1.join()
# 主線程等待t2執(zhí)行完,在往下執(zhí)行
t2.join()

# 需求:主線程等待子線程執(zhí)行完
et = time.time()
print(et-st)
image.png

2-3:守護線程

設(shè)置子線程守護主線程執(zhí)行

2-3-1:守護線程,及傳參

def func1(aa):
    for i in range(5):
        print("{}------正在做事情1-----".format(aa))
        time.sleep(1)


def func2(aaa):
    for i in range(6):
        print("{}------正在做事情2-----".format(aaa))
        time.sleep(1)


# 創(chuàng)建一個線程對象
t1 = Thread(target=func1,name="木森1",daemon=True,args=("張三",))
t2 = Thread(target=func2,name="木森2",daemon=True,kwargs={"aaa":"李四"})


# 啟動線程執(zhí)行
t1.start()
t2.start()

time.sleep(2)
print("---主線程執(zhí)行結(jié)束---")
image.png

三:線程鎖(解決多線程共享全局變量)

線程之間共用同一塊內(nèi)存,因此線程可以共享全局變量,如果多個線程同時對同一個全局變量操作,會出現(xiàn)資源競爭問題,從而數(shù)據(jù)結(jié)果會不正確。如下案例,a的預期結(jié)果應是200000,但實際結(jié)果與預期結(jié)果不符

from threading import Thread
a = 0
def work():
    global  a

    for i in range(100000):
        a += 1
    print("work執(zhí)行完:a",a)

def work2():
    global  a

    for i in range(100000):
        a += 1
    print("work2執(zhí)行完:a",a)

t1 = Thread(target=work)
t2 = Thread(target=work2 )
t1.start()
t2.start()
t1.join()
t2.join()
print("a:",a)
image.png

3-1:解決方案:Lock鎖

控制線程的執(zhí)行,避免同時獲取數(shù)據(jù),線程同步能夠保證多個線程安全訪問競爭資源,最簡單的同步機制是引入互斥鎖?;コ怄i為資源引入的一個狀態(tài)方法acquire():鎖定/方法release():釋放鎖,待鎖定。某個線程要更改共享數(shù)據(jù)時,先將其鎖定,此時資源的狀態(tài)為”鎖定“,其他線程不能更改直到該線程釋放資源,將資源的狀態(tài)變成”非鎖定“,其他的線程才能再次鎖定該資源?;コ怄i保證了每次只有一個線程進行寫入操作,從而保證了多線程情況下數(shù)據(jù)的正確性。

from threading import Thread,Lock
a = 0
# 實例化一個鎖對象
lockA = Lock()

def work():
    global  a

    for i in range(100000):
        lockA.acquire()
        a += 1
        lockA.release()

    print("work執(zhí)行完:a",a)

def work2():
    global  a

    for i in range(100000):
        lockA.acquire()
        a += 1
        lockA.release()

    print("work2執(zhí)行完:a",a)

t1 = Thread(target=work)
t2 = Thread(target=work2 )
t1.start()
t2.start()
t1.join()
t2.join()

print("a:",a)
image.png

四:練習題

一個列表中有100個url地址,每個地址請求一次,請設(shè)計程序一個程序,
使用4個線程去發(fā)送這 100個請求(假設(shè)請求每個地址需要0.5秒,請求的代碼用time.sleep(0.5)代替),
計算一共需要多長時間計算出總耗時!

import time
from threading import Thread

url_list = [f"https://www.baidu.com-{i}" for i in range(100)]


def work():
    while url_list:
        url = url_list.pop()
        print(url)
        time.sleep(0.5)


def main():
    # 創(chuàng)建4個線程
    start_time = time.time()
    ts = []
    for i in range(4):
        t1 = Thread(target=work)
        t1.start()
        ts.append(t1)

    for t in ts:
        t.join()
    end_time = time.time()
    print('執(zhí)行時間為:', end_time - start_time)

main()

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容