python信号量与线程池

Python信号量与线程池

Python信号量
  • 概述:信号量是用来 控制线程并发数的。
  • 原理:BoundedSemaphore和Semaphore管理一个内置的计数器。每当 资源释放递增时(调用acquire)计数器-1,资源消耗时递减(调用release)计数器+1。
  • 调用格式: threading.BoundedSemaphore/Semaphore(value);值默认1
  • 使用场景: 排队上厕所,一大群人上一个坑位有限的厕所
  • BoundedSemaphore和Semaphore区别: semphore() :当调用relarse()函数的时候 单纯+1 不会检查信号量的上限情况。 初始参数为0;boudedsemphore():边界信号量 当调用relarse() 会+1 , 并且会检查信号量的上限情况。不允许超过上限,使用budedsemaphore时候不允许设置初始为0,将会抛出异常,至少设置为1

注意事项: 计数器不能小于0,当计数器为0时:acquire()将阻塞线程至同步锁定状态,直到其他线程调用release()。

加入有10个人,厕所只有3个坑位
如果不加入信号量,如下:

import threading,time,random

def func (name):
   
    print(name,'进入厕所开始拉屎!!')
    time.sleep(random.randint(0,10)*1)
    print(name, '完事了!!', name, '刚占用的坑可用了')
   
name_list = ['曹操','赵云','孙悟空','花木兰','宫本武藏','露娜','程咬金','牛魔','项羽','白起']

for i in range(10):
    t=threading.Thread(target=func,args=(name_list[i],))
    t.start()

执行结果如下:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200722143205979.png在这里插入图片描述
可以看出都憋不住了,一拥而上!也不知道都是这么完事的…
加入信号量就不一样了:

import threading,time,random
semaphore=threading.BoundedSemaphore(3)  # 3个坑位
def func (name):
    semaphore.acquire()   # 获得坑位,坑位减1
    print(name,'进入厕所开始拉屎!!')
    time.sleep(random.randint(0,10)*1)
    print(name, '完事了!!', name, '刚占用的坑可用了')
    semaphore.release()# 完事,坑位加1
name_list = ['曹操','赵云','孙悟空','花木兰','宫本武藏','露娜','程咬金','牛魔','项羽','白起']

for i in range(10):
    t=threading.Thread(target=func,args=(name_list[i],))
    t.start()

执行结果如下:
在这里插入图片描述

python 线程池

线程池的基类是 concurrent.futures 模块中的 Executor,Executor 提供了两个子类,即 ThreadPoolExecutor 和 ProcessPoolExecutor,其中 ThreadPoolExecutor 用于创建线程池,而 ProcessPoolExecutor 用于创建进程池。

Exectuor 提供了如下常用方法:

  • submit(fn, *args, **kwargs):将 fn 函数提交给线程池。*args 代表传给 fn 函数的参数,*kwargs 代表以关键字参数的形式为 fn 函数传入参数。
  • map(func, *iterables, timeout=None, chunksize=1):该函数类似于全局函数 map(func, *iterables),只是该函数将会启动多个线程,以异步方式立即对 iterables 执行 map 处理。
  • shutdown(wait=True):关闭线程池。

程序将 task 函数提交(submit)给线程池后,submit 方法会返回一个 Future 对象,Future 类主要用于获取线程任务函数的返回值。由于线程任务会在新线程中以异步方式执行,因此,线程执行的函数相当于一个“将来完成”的任务,所以 Python 使用 Future 来代表。

Future 提供了如下方法:

  • cancel():取消该 Future 代表的线程任务。如果该任务正在执行,不可取消,则该方法返回 False;否则,程序会取消该任务,并返回 True。
  • cancelled():返回 Future 代表的线程任务是否被成功取消。
  • running():如果该 Future 代表的线程任务正在执行、不可被取消,该方法返回 True。
  • done():如果该 Funture 代表的线程任务被成功取消或执行完成,则该方法返回 True。
  • result(timeout=None):获取该 Future 代表的线程任务最后返回的结果。如果 Future 代表的线程任务还未完成,该方法将会阻塞当前线程,其中 timeout 参数指定最多阻塞多少秒。
  • exception(timeout=None):获取该 Future 代表的线程任务所引发的异常。如果该任务成功完成,没有异常,则该方法返回 None。
  • add_done_callback(fn):为该 Future 代表的线程任务注册一个“回调函数”,当该任务成功完成时,程序会自动触发该 fn 函数。

在用完一个线程池后,应该调用该线程池的 shutdown() 方法,该方法将启动线程池的关闭序列。调用 shutdown() 方法后的线程池不再接收新任务,但会将以前所有的已提交任务执行完成。当线程池中的所有任务都执行完成后,该线程池中的所有线程都会死亡。
同样,进程池的方式是一样的:

submit:

import threading,time,random
from concurrent.futures import ThreadPoolExecutor

def func (name):
    print(name,'进入厕所开始拉屎!!')
    time.sleep(random.randint(0,10)*1)
    print(name, '完事了!!', name, '刚占用的坑可用了')
name_list = ['曹操','赵云','孙悟空','花木兰','宫本武藏','露娜','程咬金','牛魔','项羽','白起']

poor = ThreadPoolExecutor(3)
for i in range(10):
    poor.submit(func, name_list[i])

在这里插入图片描述
map:

import threading,time,random
from concurrent.futures import ThreadPoolExecutor

def func (name):
    print(name,'进入厕所开始拉屎!!')
    time.sleep(random.randint(0,10)*1)
    print(name, '完事了!!', name, '刚占用的坑可用了')
name_list = ['曹操','赵云','孙悟空','花木兰','宫本武藏','露娜','程咬金','牛魔','项羽','白起']

poor = ThreadPoolExecutor(3)
poor.map(func, name_list)

结果如下:
在这里插入图片描述
目的都是为了控制线程的并发数。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Python线程编排是指在多线程编程中,对线程的执行顺序、同步和协调进行管理和控制的过程。常见的线程编排技术包括锁、条件变量、信号量、事件等。 1. 锁:线程锁是最基本的线程编排技术之一,用于保证在同一时间只有一个线程可以访问共享资源,避免数据竞争和并发冲突。Python中的 threading 模块提供了 Lock 类可以用来创建和管理锁。 2. 条件变量:条件变量用于线程间的通信和同步,可以让线程等待某个条件的发生或者通知其他线程某个条件已经满足。Python中的 threading 模块中提供了 Condition 类来支持条件变量。 3. 信号量信号量是一种更高级的线程编排技术,用于控制同时访问某个资源的线程数量。通过设置信号量的初始值和每次获取和释放信号量的操作,可以限制线程的并发数量。Python中的 threading 模块中提供了 Semaphore 类来支持信号量。 4. 事件:事件是一种允许线程等待或者通知的机制,通常用于线程间的同步。一个事件对象有两种状态,分别是已触发和未触发,当事件未触发时,等待该事件的线程将会被阻塞。Python中的 threading 模块中提供了 Event 类来支持事件。 此外,还有一些高级的线程编排技术,如线程池、定时任务调度等,可以进一步提高线程编排的灵活性和效率。 需要注意的是,在Python中,由于全局解释器锁(GIL)的存在,多线程并不能充分利用多核处理器的性能。如果需要充分利用多核处理器,可以考虑使用多进程编程或者其他并发编程模型。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值