Python高级编程之 线程
1. 多任务
定义:
有很多的场景中的事情是同时进行的,比如开车的时候 手和脚共同来驾驶汽车,再比如唱歌跳舞也是同时进行的
程序中模拟多任务
import time
def sing():
for i in range(3):
print("正在唱歌...%d"%i)
time.sleep(1)
def dance():
for i in range(3):
print("正在跳舞...%d"%i)
time.sleep(1)
if __name__ == '__main__':
sing()
dance()
多任务的理解
- 并行:真的多任务 cpu大于当前执行的任务
- 并发:假的多任务 cpu小于当前执行的任务(PC主要都是这种为主)
2. 线程
线程完成多任务
import threading
import time
def demo():
# 子线程
print("hello girls")
time.sleep(1)
if __name__ == '__main__':
for i in range(5):
t = threading.Thread(tatget=demo)
t.start()
查看线程数量
threading.enumerate() # 查看当前线程数量
验证字线程的执行与创建
- 当调用Thread的时候,不会创建线程。
- 当调用Thread创建出来的实例对象的start方法的时候,才会创建线程以及开始运行这个线程。
继承Thread类创建线程
import threading
import time
class A(threading.Thread):
def __init__(self,name):
super().__init__(name=name)
def run(self):
for i in range(5):
print(i)
if __name__ == '__main__':
t = A('test_name')
t.start
多线程共享全局变量()线程间通信
在一个函数中,对全局变量进行修改的时候,是否要加global要看是否对全局变量的指向进行了修改,如果修改
了指向,那么必须使用global,仅仅是修改了指向的空间中的数据,此时不用必须使用global
多线程参数-args
threading.Thread(target=test, args=(num, ))
共享全局变量资源竞争
一个线程写入读取没问题,当有两个线程写入时,可以添加互斥锁进行控制
互斥锁
某个线程要更改共享数据时,先将其锁定,此时资源的状态为"锁定",其他线程不能改变,只到该线程释放资源,将资源的状态变成"非锁定",其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。
互斥锁用法:
扫描二维码关注公众号,回复:
9139605 查看本文章
# 创建锁
mutex = threading.Lock() # 单个锁
mutex = threading.RLock() # 可重复上锁
# 锁定
mutex.acquire() # 再需要上锁的语句前一行
# 解锁
mutex.release()
死锁
定义:在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。
import threading
import time
class MyThread1(threading.Thread): # ...
def run(self):
# 对mutexA上锁
mutexA.acquire()
# mutexA上锁后,延时1秒,等待另一个线程对mutexB上锁
print(self.name+'----do1---up----')
time.sleep(1)
# 此时会堵塞
mutexB.acquire()
print(self.name+'----do1---down----')
mutexB.release()
# 对mutexA解锁
mutexA.release()
class MyThread2(threading.Thread):
def run(self):
# 对mutexB上锁
mutexB.acquire()
# mutexB上锁后,延时1秒,等待另一个线程对mutexA上锁
print(self.name+'----do2---uo----')
time.sleep(1)
# 此时会堵塞,因为这个mutexA已经被另外的线程抢先上锁了
mutexA.acquire()
print(self.name+'----do2---down----')
mutexA.release()
# 对mutexB解锁
mutexB.release()
mutexA = threading.Lock()
mutexB = threading.Lock()
if __name__ == '__main__':
t1 = MyThreading1()
t2 = Mythreading2()
t1.start()
t2.start()
如何避免死锁:
- 程序设计时要尽量避免
- 添加超市时间等(timeout=xx)
线程同步
天猫,小爱案例:
-
天猫精灵:小爱同学
-
小爱同学:在
-
天猫精灵:现在几点了?
-
小爱同学:你猜猜现在几点了
import threading
class XiaoAi(threading.Thread):
def __init__(self, cond):
super().__init__(name='小爱同学')
# self.lock = lock
self.cond = cond
def run(self):
with self.cond:
print(4)
self.wait()
print(5)
print("{}:在".format(self.name))
self.cond.notify()
self.cond.wait()
print("{}:你猜猜现在几点了".format(self.name))
self.cond.notify()
class TianMao(threading.Thread):
def __init__(self, cond):
super().__init__(name='天猫精灵')
self.cond = cond
def run(self):
self.cond.acquire()
print("{}:小爱同学".format(self.name))
print(1)
self.cond.notify()
print(2)
self.cond.wait()
print(3)
print("{}:现在几点了?".format(self.name))
self.cond.notify()
self.cond.wait()
self.cond.release()
class Sir(threading.Thread):
def __init__(self, cond):
super().__init__(name='Sir')
self.cond = cond
def run(self):
self.cond.acquire()
print("{}:小爱同学".format(self.name))
print(1)
self.cond.notify()
print(2)
self.cond.wait()
print(3)
print("{}:现在几点了?".format(self.name))
self.cond.notify()
self.cond.wait()
self.cond.release()
if __name__ == '__main__':
mutex = threading.Rlock()
cond = threading.Condition()
Xiaoai = XiaoAi(cond)
tianmao = TianMao(cond)
sir = Sir(cond)
# 启动顺序很重要
xiaoai.start()
tianmao.start()
sir.start()
多任务版udp聊天
流程:
- 创建套接字
- 绑定本地信息
- 获取对方ip和端口
- 发送、接收数据
- 创建两个线程,去执行功能
案例参考:
import socket
import threading
def recv_msg(udp_socket):
"""发送数据"""
while True:
recv_data = udp_socket.ercvfrom(1024)
print(recv_data)
def send_msg(udp_socket, dest_ip, dest_port):
"""接收数据"""
while True:
send_data = input("输入要发送数据:")
udp_socket.sendto(send_data.encode('gbk'), (dest_ip, dest_port))
def main():
"""聊天器"""
# 创建套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定
udp_socket.bind(("", 7810))
# 获取ip和端口
dest_ip = input("请输入对方ip:")
dest_port = int(input("请输入对方port:"))
# 创建线程
t_recv = threading.Thread(target=recv_msg, args=(udp_socket, ))
t_send = threading.Thread(target=send_msg, args=(udp_socket, dest_ip, dest_port))
# 运行
t_recv.start()
t_send.start()
if __name__ == '__main__':
main()