python之多任務
- 2019 年 10 月 6 日
- 筆記
多任務
什麼是多任務?
通俗點說就是同一時間干多件事。
多線程實例:我們在看電影的時候一般會吃爆米花,這是同時進行的,
首先沒有多線程的情況
import time
def movietheaters():
for i in range(3):
print('我在看電影')
time.sleep(1)
def foodGotEaten():
for i in range(3):
print('我在吃爆米花')
time.sleep(1)
def main():
movietheaters()
foodGotEaten()
if __name__ == "__main__":
main()
執行結果:
我在看電影
我在看電影
我在看電影
我在吃爆米花
我在吃爆米花
我在吃爆米花
這顯然不是我們想要的,我們想要的是同時進行。
修改成如下:
import time
import threading
def movietheaters():
for i in range(3):
print('我在看電影')
time.sleep(1)
def foodGotEaten():
for i in range(3):
print('我在吃爆米花')
time.sleep(1)
def main():
th1 = threading.Thread(target=movietheaters)
th2 = threading.Thread(target=foodGotEaten)
th1.start()
th2.start()
if __name__ == "__main__":
main()
運行結果:
我在看電影
我在吃爆米花
我在看電影
我在吃爆米花
我在看電影
我在吃爆米花
自己在寫的時候可以看到是兩個兩個同時輸出的。
查看線程數
實例:
import threading
import time
def test1():
for i in range(3):
time.sleep(1)
print("test1===%d"%i)
def test2():
for i in range(3):
time.sleep(1)
print("test2===%d"%i)
def main():
t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test2)
t1.start()
t2.start()
# 查看所有線程
print(threading.enumerate())
lenth = len(threading.enumerate())
print('線程數為:%d'%lenth)
if __name__ == "__main__":
main()
# 我們把t1.start()叫做主線程,執行的函數叫做子線程,當函數執行完表示該線程結束。創建一個線程是在start()函數執行後。
類創建線程
方法創建線程像上面那樣寫,類創建線程就不行了,我們需要通過繼承的方式來。
實例:
import threading
import time
class testThreading(threading.Thread):
def run(self):
for i in range(3):
time.sleep(1)
print('—–%d'%i)
if __name__ == '__main__':
t = testThreading()
t.start()
注意:在start()的時候自動調用run方法。如果你的類中還有其他方法,需要在run方法中調用。
多線程修改全局變量
num = 1
def test1():
global num
num+=2
print(num)
test1()
print(num)
我們再修改一個不可變全局變量時候添加了一個global,說明他是一個全局變量。
修改成多線程:
import threading
num = 1
def test1():
global num
num +=1
def test2():
print("test2的num值為:%d"%num)
def main():
t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test2)
t1.start()
t2.start()
if __name__ == '__main__':
main()
輸出:test2的num值為:2
說明修改生效了,說明在多線程中,全局變量是共享的。
線程帶參數
import threading
list = [1,2,3]
def test1(list):
list.append(4)
def test2(list):
print("test2的num值為:%s"%list)
def main():
t1 = threading.Thread(target=test1,args = (list,))
t2 = threading.Thread(target=test2,args = (list,))
t1.start()
t2.start()
if __name__ == '__main__':
main()
輸出結果:test2的num值為:[1, 2, 3, 4]
添加參數:在Thread函數中加一個參數args,類型必須為元組
同樣我們在test2中輸出的也是帶有4的列表,說明參數也是共享的。
多線程共享變量存在的問題
1、資源競爭
兩個方法同時引用一個全局變量,就會出現資源競爭的情況。
例如:
import threading
import time
num = 0
def test1():
global num
for i in range(1000000):
num+=1
print("test1的num是:%d"%num)
def test2():
global num
for i in range(1000000):
num+=1
print("test2的num是:%d"%num)
def main():
t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test2)
t1.start()
t2.start()
time.sleep(5)
print(num)
if __name__ == '__main__':
main()
輸出:
test2的num是:1146736
test1的num是:1203787
1203787
不是應該是2000000嗎?很明顯出錯了!出現這種情況的原因就是同時拿num值,可能上一個方法還沒有賦值,所以就加少了。怎麼解決?那我就讓他一次做完。也就是同步,同步的意思不是說一起,而是協同步調,按照前後次序進行運行,那就要引出一個新概念,互斥鎖。我在執行test1的時候把他鎖住,不讓他執行test2。
互斥鎖
#注意:同一個鎖,在同一時間只能鎖一次。會發生堵塞
# 創建一個鎖,莫認沒有上鎖
mutex = threading.Lock()
# 上鎖
mutex.acquire()
# 解鎖
mutex.release()
將上面的實例修改成:
import threading
import time
num = 0
mutex = threading.Lock()
def test1():
global num
mutex.acquire()
for i in range(1000000):
num+=1
mutex.release()
print("test1的num是:%d"%num)
def test2():
global num
mutex.acquire()
for i in range(1000000):
num+=1
mutex.release()
print("test2的num是:%d"%num)
def main():
t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test2)
t1.start()
t2.start()
time.sleep(5)
print(num)
if __name__ == '__main__':
main()
輸出:
test1的num是:1000000
test2的num是:2000000
2000000
解決。
但是互斥鎖可以存在多個,但是一多,就會出現問題。出現死鎖的情況,就是都堵塞了。
解決方法就是:添加超時時間(給一個時間,到了時間就解鎖),等其他方法。
利用多線程進行udp同時收和發數據實例
import socket
import threading
def main():
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
udp_socket.bind(("",7890))
dest_ip = input("請輸入對方的ip:")
dest_port = int(input("請輸入對方的接收端口:"))
t1 = threading.Thread(target=Send, args = (udp_socket,))
t2 = threading.Thread(target=Receive, args = (udp_socket,dest_ip,dest_port))
t1.start()
t2.start()
def Send(udp_socket,dest_ip,dest_port):
while True:
send_data = input("請輸入需要發送的消息:")
udp_socket.sendto(send_data.encode("utf-8"),(dest_ip,dest_port))
def Receive(udp_socket):
while True:
recv_data = udp_socket.recvfrom(1024)
print(recv_data[0].decode("gbk"))
if __name__ == "__main__":
main()