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