Python 线程间同步之信号量Semaphore

用处

信号量semaphore 是用于控制进入数量的锁。有哪些应用场景呢,比如说在读写文件的时候,一般只能只有一个线程在写,而读可以有多个线程同时进行,如果需要限制同时读文件的线程个数,这时候就可以用到信号量了(如果用互斥锁,就是限制同一时刻只能有一个线程读取文件)。又比如在做爬虫的时候,有时候爬取速度太快了,会导致被网站禁止,所以这个时候就需要控制爬虫爬取网站的频率。

实例

semaphore内部维护了一个条件变量condition,构造函数是:

Semaphore(value=1) # value设置是内部维护的计数器的大小,默认为1. 

主要有两个方法:

每当调用acquire()时,内置计数器-1,直到为0的时候阻塞
每当调用release()时,内置计数器+1,并让某个线程的acquire()从阻塞变为不阻塞

用爬虫来举例,假如说有一个UrlProducer线程,爬取url,多个htmlSpider线程,爬取url对应的网页。如果直接开20个htmlSpider线程,20个线程是同时执行的,现在要限制同时执行能执行三个,就可以使用信号量来控制:

import threading
import time
class htmlSpider(threading.Thread):
    def __init__(self, url, sem):
        super().__init__()
        self.url = url
        self.sem = sem

    def run(self):
        time.sleep(2)
        print("got html text success")
        self.sem.release() # 内部维护的计数器加1,并通知内部维护的conditon通知acquire

class UrlProducer(threading.Thread):
    def __init__(self, sem):
        super().__init__()
        self.sem = sem

    def run(self):
        for i in range(20):
            self.sem.acquire() # 内部维护的计数器减1,到0就会阻塞
            html_thread = htmlSpider("http://baidu.com/{}".format(i), self.sem)
            html_thread.start()

if __name__ == "__main__":
    sem = threading.Semaphore(3) #设置同时最多3个
    url_producer = UrlProducer(sem)
    url_producer.start()

从结果可以看出,每次都几乎是三个同时的完成任务。

源码分析

1.init方法

Semaphore类的构造函数传入接收一个参数value,设置内部计数器的大小。调用release()时将这个值加1,调用acquire()时减1。

2.wait方法

wait方法并不复杂,每次调用acquire,内部技术器就减1,当计数器为0的时候,就等待通知。

3.release方法

在看release方法的时候,突然发现,条件变量的notify方法,在没有线程等待的时候,也是可以调用的,不用抛出异常。所以这里不用判断内部计数器是不是0,而是每次都可以调用notify

总结

  • 信号量semaphore 可以控制同时运行执行的线程数量。
  • 信号量semaphore内部维护了一个条件变量和一个计数器。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python 的多线程编程中,为了避免资源竞争和数据不一致的问题,我们需要使用同步机制来保证线程的协调。以下是几种常用的同步机制: 1. Lock(锁):Lock 是最基本的同步机制之一,它可以确保在同一时只有一个线程可以访问共享资源。 2. RLock(可重入锁):RLock 是 Lock 的升级版,它允许同一个线程多次获得锁,从而避免了死锁的问题。 3. Semaphore信号量):Semaphore 是一种计数器,它用来控制对共享资源的访问数量。当计数器为 1 时,Semaphore 就相当于 Lock;当计数器大于 1 时,Semaphore 就可以允许多个线程同时访问共享资源。 4. Condition(条件变量):Condition 是一种高级的同步机制,它允许线程在某个条件满足时被唤醒。通常情况下,Condition 和 Lock 一起使用,来实现线程的协调和通信。 5. Event(事件):Event 是一种简单的同步机制,它允许线程在某个事件发生时被唤醒。通常情况下,Event 被用来协调多个线程的启动和停止。 6. Barrier(屏障):Barrier 是一种同步机制,它可以让多个线程在某个点上进行同步,即所有线程必须同时到达该点才能继续执行。 以上是常见的同步机制,具体使用哪种机制则根据实际需求而定。在使用多线程编程时,需要注意线程的协调和通信,避免出现资源竞争和数据不一致的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值