Python高级编程之 线程

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聊天
流程:

  1. 创建套接字
  2. 绑定本地信息
  3. 获取对方ip和端口
  4. 发送、接收数据
  5. 创建两个线程,去执行功能

案例参考:

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()
发布了27 篇原创文章 · 获赞 11 · 访问量 1483

猜你喜欢

转载自blog.csdn.net/weixin_45550881/article/details/103932023