1. 程式人生 > >多工一(多執行緒基礎)

多工一(多執行緒基礎)

併發,並行

併發:指的是任務數多餘cpu核數,通過作業系統的各種任務排程演算法,實現用多個任務“一起”執行(實際上總有一些任務不在執行,因為切換任務的速度相當快,看上去一起執行而已)
並行:指的是任務數小於等於cpu核數,即任務真的是一起執行的

多執行緒執行:

  • 匯入執行緒模組:

#匯入執行緒模組
import threading

  • 執行緒類Thread引數說明

Thread([group [, target [, name [, args [, kwargs]]]]])
group: 執行緒組,目前只能使用None
target: 執行的目標任務名
args: 以元組的方式給執行任務傳參
kwargs: 以字典方式給執行任務傳參
name: 執行緒名,一般不用設定

  • 啟動執行緒

啟動執行緒使用start方法

互斥鎖概念

  • 互斥鎖: 對共享資料進行鎖定,保證同一時刻只能有一個執行緒去操作

注意:
搶到鎖的執行緒先執行,沒有搶到鎖的執行緒需要等待,等鎖用完後需要釋放,然後其它等待的執行緒再去搶這個鎖,那個執行緒搶到那個執行緒再執行。
具體那個執行緒搶到這個鎖我們決定不了,是由cpu排程決定的。

執行緒注意點

1.全域性變數執行緒之間資料共享
2.執行緒之間執行是沒有順序的
3.全域性變數上鎖,必須上同一把鎖,上鎖以後效率會變慢
4.工作中要避免死鎖
5.主執行緒會等待所有的子執行緒結束而結束
6.守護主執行緒,主執行緒結束後守護的子執行緒結束

執行緒零碎知識點

  • 檢視執行緒個數的函式 -----> threading.enumerate()
  • 多執行緒共享全域性變數

程式碼

多執行緒共享全域性變數的問題(引入互斥鎖)

# 兩個同時去操作我們的資料,例如都加1
# 全域性變數多個執行緒同時去修改的時候會有問題
# 全域性變數上鎖,必須上同一把鎖,上鎖以後效率會變慢
import threading

import time

num = 0

# 建立一把鎖
lock = threading.Lock()
# 寫1
def write1():
    global num
    for temp in range(
10000000): # 鎖上 lock.acquire() # print('w') num += 1 # 解鎖 lock.release() # cpu分成三步處理 # 1. 得到num的值 # 2. num的值加1 # 3. 把修改後的值賦值給num print("write1結束") # 寫2 def write2(): global num for temp in range(10000000): # 鎖上 lock.acquire() # print('q') num += 1 # 解鎖 lock.release() print("write2結束") def main(): """全域性變數同時操作實驗""" # 開啟寫的執行緒1 threading.Thread(target=write1).start() threading.Thread(target=write2).start() # 為了計算準確,睡2秒 time.sleep(30) print("全域性變數", num) if __name__ == '__main__': main()

多執行緒版聊天機器人(設定守護主執行緒)

# 建立一個tcp伺服器端
# 1. 初始化
# 2. 繫結埠
# 3. 設定被動模式
# 4. 迴圈接收使用者的請求
# 5. 處理使用者的請求
# 6. 關閉
import socket
import threading


def client_exec(client):
    """
    這個客戶端的處理
    :param client: 客戶端連線的物件
    :return: NONE
    """

    while True:

        # 判斷客戶端是否關閉了,判斷髮送過來的資料,如果是空的,那麼退出迴圈,如果不是空的,那回個資訊
        data = client.recv(1024)
        # 判斷是否有資料
        if data:
            # 說明有資料n
            # 解析 資料
            data_decode = data.decode("utf-8")

            # 您的資料已收到
            send_data = "您的資料已收到%s" % data_decode
            client.send(send_data.encode("utf-8"))
        else:
            # 說明沒有資料,
            # 退出迴圈
            break

    # 關閉客戶端
    client.close()


def main():
    """聊天機器人"""
    # 1.初始化
    tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 2. 繫結埠
    tcp_server.bind(("", 8181))

    # 3. 設定被動模式
    tcp_server.listen(128)

    # 4. 迴圈接收使用者的請求
    while True:
        # 接收
        client, address = tcp_server.accept()

        # 處理使用者的請求
        # 一個函式一個功能
        # # 客戶端的執行緒
        client_thread = threading.Thread(target=client_exec, args=(client,))
        # 開啟執行緒
        client_thread.start()
        # 守護主執行緒的作用是主執行緒執行緒以後子執行緒全部結束,前提執行緒必須設定守護
        # threading.Thread(target=client_exec, args=(client,), daemon=True).start()
    # client_exec(client)

    # 關閉
    tcp_server.close()


if __name__ == '__main__':
    main()

一邊唱歌一邊跳舞檢視執行緒數

import threading
import time


def dance():
    print("跳舞", threading.enumerate())  # 檢視執行緒
    """跳舞"""
    while True:
        print("跳舞")
        time.sleep(1)


def song():
    print("唱歌", threading.enumerate())  # 檢視執行緒
    """唱歌"""
    while True:
        print("唱歌")
        time.sleep(1)


def main():
    """一邊跳舞,一邊唱歌"""
    # # 跳舞
    # dance()
    #
    # # 唱歌
    # song()

    # 函式或者方法 api
    print(threading.enumerate())  # 檢視執行緒

    # dance()
    # # 開啟唱歌的執行緒
    threading.Thread(target=song).start()

    # 開啟唱歌的執行緒
    threading.Thread(target=dance).start()


if __name__ == '__main__':
    main()
執行結果:
[<_MainThread(MainThread, started 17052)>]
唱歌 [<_MainThread(MainThread, started 17052)>, <Thread(Thread-1, started 7680)>]
唱歌
跳舞 [<_MainThread(MainThread, started 17052)>, <Thread(Thread-1, started 7680)>, <Thread(Thread-2, started 19568)>]
跳舞
唱歌