ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
![](https://img.kancloud.cn/41/e0/41e066af9a6c25a24868d9667253ec98_1241x333.jpg) ***** ## 多任务 有很多的场景中的事情是同时进行的,比如开车的时候 手和脚共同来驾驶汽车,再比如唱歌跳舞也是同时进行的 ### 程序中模拟多任务 ~~~ 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() ~~~ ### 多任务的理解 ![](https://img.kancloud.cn/7e/f5/7ef564247d3b0e8325f0e76ce8b325af_820x433.png) - 并行:真的多任务 cpu大于当前执行的任务 - 并发:假的多任务 cpu小于当前执行的任务 ### 线程完成多任务 ~~~ import threading import time def demo(): # 子线程 print("hello girls") time.sleep(1) if __name__ == "__main__": for i in range(5): t = threading.Thread(target=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嘛? <br>在一个函数中,对全局变量进行修改的时候,是否要加global要看是否对全局变量的指向进行了修改,如果修改了指向,那么必须使用global,仅仅是修改了指向的空间中的数据,此时不用必须使用global ### 多线程参数-args ~~~ threading.Thread(target=test, args=(num,)) ~~~ ### 共享全局变量资源竞争 一个线程写入,一个线程读取,没问题,如果两个线程都写入呢? ### 互斥锁 当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制 <br>某个线程要更改共享数据时,先将其锁定,此时资源的状态为"锁定",其他线程不能改变,只到该线程释放资源,将资源的状态变成"非锁定",其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。 ~~~ 创建锁 mutex = threading.Lock() 锁定 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已经被另外的线程抢先上锁了 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---up----') 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 = MyThread1() t2 = MyThread2() t1.start() t2.start() ~~~ ### 避免死锁 - 程序设计时要尽量避免 - 添加超时时间等 ### 线程同步 天猫精灵:小爱同学 小爱同学:在 天猫精灵:现在几点了? 小爱同学:你猜猜现在几点了 ### 多任务版udp聊天 1 创建套接字 2 绑定本地信息 3 获取对方IP和端口 4 发送、接收数据 5 创建两个线程,去执行功能