异步 信号量

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yangxiaodong88/article/details/86480189

tornado 中的 信号量

1 自己手动 释放

from tornado import gen
from tornado.ioloop import IOLoop
from tornado.locks import Semaphore

sem = Semaphore(2)

async def worker(worker_id):
    await sem.acquire()
    try:
        print("Worker %d is working" % worker_id)
        await use_some_resource()
    finally:
        print("Worker %d is done" % worker_id)
        sem.release()

async def runner():
    # Join all workers.
    await gen.multi([worker(i) for i in range(3)])

IOLoop.current().run_sync(runner)

2 使用上下文管理 with 自动释放

async def worker(worker_id):
    async with sem:
        print("Worker %d is working" % worker_id)
        await use_some_resource()

    # Now the semaphore has been released.
    print("Worker %d is done" % worker_id)

信号量 理解

上面的tornado sem = Semaphore(2) 允许激活2个这个协程

现在放入线程中来说, 线程间同步之信号量Semaphore
信号量是控制进入数量的锁。 应用场景, 比如再读写文件的时候, 一般只能有一个文件在写, 而读可以有多个线程同时进行,如果需要限制同时读取文件的个数, 这个时候可以用到信号量(如果用互斥锁, 就是限制同一时刻只能有一个线程读取文件)。又比如再做爬虫的时候, 有时候跑去速度太快, 会被网站禁止, 这个时候就要控制爬取的频率的。

semaphore 是一个内部计数器

  • 每当调用acquire()时候, 内置计数器 减1
  • 每当调用release()时候, 内置计数器 加1
    计数器不能 小于0 当计数器为0时候, acquire() 将阻塞线程直到其他线程调用release()

如果在主机执行IO密集型任务的时候再执行这种类型的程序时,计算机就有很大可能会宕机。
这时候就可以为这段程序添加一个计数器功能,来限制一个时间点内的线程数量。

当我们在分析网络代码客户端来说, 一定要使用某种限流机制, 防止向服务器发起太多并发请求。如果服务器负载过大, 那么系统的整体性能可能会降低。在多线程中可以使用 线程池, 在异步请求中就像tornado 中使用信号量。限制协程的数量,Semaphore 对象维护着一个内部计数器,若在对象上调用 .acquire() 协程方法,计数
器则递减;若在对象上调用 .release() 协程方法,计数器则递增。计数器的初始值在实
例化 Semaphore 时设定
就像asyncio 中信号量

semaphore = asyncio.Semaphore(concur_req)

如果计数器大于零,那么调用 .acquire() 方法不会阻塞;可是,如果计数器为零,那么
.acquire() 方法会阻塞调用这个方法的协程,直到其他协程在同一个 Semaphore 对象
上调用 .release() 方法,让计数器递增

总结:
在多线程中
信号量semaphore 可以控制同时运行执行的线程数量。
信号量semaphore内部维护了一个条件变量和一个计数器。

猜你喜欢

转载自blog.csdn.net/yangxiaodong88/article/details/86480189
今日推荐