1. 多任务的概念
? ? ? ? 就是操作系统可以同时运行多个任务,真正的并行多任务只能在多核CPU上运行,但是由于任务数量远远多于CPU的核心数量,操作系统会自动把多任务轮流调度到每个核心上执行。
单核CPU通过时间片轮转/优先级调度(操作系统的算法)实现多个任务几乎同时执行
并发:多个任务同时执行,任务数<=CPU核心数
并行:多个任务"同时"执行,任务数>CPU核心数
线程的运行是没有先后顺序的,由操作系统说了算
2. 线程-demo
import time
from threading import Thread, enumerate
def sing():
for i in range(4):
print("-----正在唱:菊花茶-----")
time.sleep(0.1)
def dance():
for i in range(6):
print("-----正在跳舞-----")
time.sleep(0.1)
def main():
# 创建线程实例
t1 = Thread(target=sing) # 当这个函数运行完毕后,意味着子线程结束了
t2 = Thread(target=dance)
# 开启线程
t1.start() # 启动线程,让线程开始执行
t2.start()
while True:
print(enumerate())
time.sleep(0.1)
if len(enumerate()) <= 1:
print(enumerate())
break
if __name__ == '__main__':
main()
3.? 验证何时创建线程,也就是线程列表里面包含了子线程
import time
from threading import Thread, enumerate
def sing():
for i in range(4):
print("-----正在唱:菊花茶-----")
time.sleep(0.1)
def main():
# 创建线程实例
print(enumerate())
t1 = Thread(target=sing) # 当这个函数运行完毕后,意味着子线程结束了
print(enumerate())
# 开启线程
t1.start() # 启动线程,让线程开始执行
print(enumerate())
if __name__ == '__main__':
main()
Thread()实例化一个对象的时候并不会创建线程,只有在调用线程实例的start方法时,才会真正创建线程,并执行线程。
4. 通过自定义类(继承自threading.Thread类)来实现多线程
import threading
import time
class MyThread(threading.Thread):
"""通过类实现多线程"""
def run(self):
"""run方法执行完毕,线程结束"""
for i in range(5):
time.sleep(1)
print(f"I am {self.name}")
if __name__ == '__main__':
t1 = MyThread()
t2 = MyThread()
print(threading.enumerate())
t1.start()
t2.start()
print(threading.enumerate())
5.? 多线程共享全局变量,但是如何避免资源竞争,互斥锁
?
import threading
num = 0
def test01():
global num
for x in range(1000000):
# 上锁,如果之前没被上锁,那么此时上锁成功
# 如果上锁之前已经被上锁了,那么会堵塞在这里,直到这个锁被解开为止
# 上锁有一个原则,上锁的代码越少越好
lock.acquire()
num += 1
# 解锁
lock.release()
def test02():
global num
for x in range(1000000):
lock.acquire()
num += 1
lock.release()
# 定义一个锁的全局变量
lock = threading.Lock()
if __name__ == '__main__':
t1 = threading.Thread(target=test01)
t2 = threading.Thread(target=test02)
t1.start()
t2.start()
t1.join()
t2.join()
print(num)
6.? 死锁
概念:在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方资源的时候,就会造成死锁。
import time
import threading
class MyThread1(threading.Thread):
def run(self):
MutexA.acquire()
print(self.getName(), "----do1--up----")
time.sleep(1)
MutexB.acquire()
print(self.getName(), "----do1--down----")
MutexB.release()
MutexA.release()
class MyThread2(threading.Thread):
def run(self):
MutexB.acquire()
print(self.getName(), "----do2--up----")
time.sleep(1)
MutexA.acquire()
print(self.getName(), "----do2--down----")
MutexA.release()
MutexB.release()
# 创建两个互斥锁
MutexA = threading.Lock()
MutexB = threading.Lock()
def main():
t1 = MyThread1()
t2 = MyThread2()
t1.start()
t2.start()
t1.join()
t2.join()
if __name__ == '__main__':
main()
避免死锁:
(1)程序设计时要尽量避免(银行家算法)
(2)添加超时时间
7. 多线程-udp聊天器
import time
import threading
import socket
def recv(tasks_socket):
while True:
recv_data = tasks_socket.recvfrom(1024)
print(f"接收到的数据是:{recv_data[0].decode()}")
def send(tasks_socket, dest_ip, dest_port):
while True:
time.sleep(0.01)
send_data = input("请输入要发送的数据")
tasks_socket.sendto(send_data.encode(), (dest_ip, dest_port))
def main():
tasks_socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
tasks_socket.bind(("", 8000))
dest_ip = input("请输入对方IP:")
dest_port = int(input("请输入对方Port:"))
t1 = threading.Thread(target=send, args=(tasks_socket, dest_ip, dest_port))
t2 = threading.Thread(target=recv, args=(tasks_socket,))
t1.start()
t2.start()
if __name__ == '__main__':
main()
|