多个线程在同一个进程中运行,多个线程共享这个进程中的全局变量
import threading,time
ticket=50 # 代表50张车票
def sale_ticket():
global ticket
# 每个排队窗口100人
for i in range(100):
if ticket>0:
print(f'{threading.current_thread().name}正在出售第{ticket}张票')
ticket-=1
time.sleep(1)
if __name__ == '__main__':
for i in range(3):
t=threading.Thread(target=sale_ticket)
t.start()
'''
Thread-3正在出售第11张票Thread-1正在出售第11张票Thread-2正在出售第11张票
多线程操作数据带来不安全的问题,可能会多个线程同时访问公共资源/临界区,造成数据错误
'''
采用Lock锁对象去解决这类问题。
上锁:acquire()方法
解锁:release()方法
代码实例:
import threading,time
ticket=50 # 代表50张车票
# 创建锁对象
lock_obj=threading.Lock()
def sale_ticket():
global ticket
# 每个排队窗口100人
for i in range(100):
lock_obj.acquire() # 上锁
if ticket>0:
print(f'{threading.current_thread().name}正在出售第{ticket}张票')
ticket-=1
lock_obj.release() # 解锁
time.sleep(1)
if __name__ == '__main__':
for i in range(3):
t=threading.Thread(target=sale_ticket)
t.start()
是线程模型中的经典问题,与编程语言无关。
当程序中出现了明确的两类任务,一个任务负责生产数据,另一个任务负责处理生产的数据时,就可以使用该模式
Python内置模块queue中的Queue类
方法名称 | 功能描述 |
---|---|
put(item) | 向队列中放置数据,若队列为满,则阻塞 |
get() | 从队列中取走数据,若队列为空,则阻塞 |
join() | 若队列不为空,则等待队列为空 |
task_done() | 消费者从队列中取走一项数据,当队列变为空时,唤醒调用join() 的线程 |
代码实例:
import threading,queue,time
# 创建一个生产者类
class Producer(threading.Thread):
def __init__(self,name,queue):
threading.Thread.__init__(self,name=name) # 使用super()会报错,原因不知道
self.queue=queue
def run(self):
for i in range(1,6):
print(f'生产者线程{self.name}将产品{i}放入队列')
self.queue.put(i)
time.sleep(1)
print('生产者完成了所有数据的存放')
# 创建一个消费者类
class Consumer(threading.Thread):
def __init__(self,name,queue):
threading.Thread.__init__(self,name=name) # 使用super()会报错,原因不知道
self.queue=queue
def run(self):
for _ in range(5):
value=self.queue.get()
print(f'消费者线程{self.name}取出了产品{value}')
time.sleep(1)
print('消费者完成了所有数据的取出')
if __name__ == '__main__':
print('主线程开始执行')
# 创建队列
q=queue.Queue()
# 创建生产者线程
p=Producer('Producer',q)
# 创建消费者线程
c=Consumer('Consumer',q)
p.start()
c.start()
p.join()
c.join()
print('主线程执行结束')