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()