多工一(多執行緒基礎)
阿新 • • 發佈:2019-01-08
併發,並行
併發:指的是任務數多餘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)>]
跳舞
唱歌