首页 > 编程语言 >信号量的秘密:Python中的Semaphore详解

信号量的秘密:Python中的Semaphore详解

时间:2024-09-28 11:23:49浏览次数:10  
标签:访问 Python Semaphore 信号量 threading 线程 url semaphore

引言

随着计算机硬件的发展,多核处理器已经成为了标准配置。这使得开发人员可以利用并发编程技术来提高应用程序的性能。然而,在并发环境下,资源共享和访问控制成了一个棘手的问题。Semaphore(信号量)就是一种常用的解决此类问题的技术。通过限制对共享资源的同时访问数量,Semaphore可以有效地防止资源的竞争条件,保证程序的正确性。

Semaphore主要有两种类型:二进制信号量和计数信号量。前者只能在0和1之间切换,通常用于互斥锁;后者则可以有任意非负整数值,用于控制同时访问某个资源的线程数量。

接下来,我们将详细介绍Semaphore的基础知识,并通过一些实用的例子来展示其在实际开发中的应用。

基础语法介绍

在Python中,Semaphore可以通过threading模块获取。下面是一个简单的Semaphore对象创建示例:

import threading

# 创建一个初始值为5的Semaphore对象
semaphore = threading.Semaphore(5)

Semaphore的主要方法包括:

  • acquire([blocking[, timeout]]):尝试获取一个许可。如果blocking为True且Semaphore当前没有可用许可,则会阻塞直到获得许可或超时。
  • release():释放一个之前获取的许可。如果当前Semaphore的值已经达到最大值,则该操作无效。

基础实例

假设我们有一个网站,同时只能允许5个用户访问。我们可以使用Semaphore来模拟这个场景:

import threading
import time

# 创建一个初始值为5的Semaphore对象
semaphore = threading.Semaphore(5)

def access_website():
    # 尝试获取一个许可
    semaphore.acquire()
    
    print(f"{threading.current_thread().name} 正在访问网站")
    time.sleep(2)  # 模拟访问时间
    
    print(f"{threading.current_thread().name} 已完成访问")
    # 释放许可
    semaphore.release()

# 创建多个线程模拟用户访问
threads = []
for i in range(10):
    t = threading.Thread(target=access_website)
    threads.append(t)
    t.start()

# 等待所有线程执行完毕
for t in threads:
    t.join()

在这个例子中,我们定义了一个access_website函数来模拟用户访问网站的行为。通过Semaphore的acquirerelease方法,我们成功地限制了同时访问的数量。

进阶实例

在更复杂的场景下,我们可能需要处理多个不同类型的资源访问限制。这时候,我们可以为每种资源创建一个独立的Semaphore对象,从而实现更加灵活的控制。

例如,假设我们的网站除了普通用户访问外,还有管理员登录的功能。我们可以分别为这两种操作设置不同的访问限制:

import threading
import time

# 创建两个Semaphore对象,分别用于限制普通用户访问和管理员登录
user_semaphore = threading.Semaphore(5)
admin_semaphore = threading.Semaphore(2)

def user_access():
    user_semaphore.acquire()
    print(f"{threading.current_thread().name} 用户正在访问")
    time.sleep(2)
    print(f"{threading.current_thread().name} 用户访问结束")
    user_semaphore.release()

def admin_login():
    admin_semaphore.acquire()
    print(f"{threading.current_thread().name} 管理员正在登录")
    time.sleep(3)
    print(f"{threading.current_thread().name} 管理员登录结束")
    admin_semaphore.release()

# 创建多个线程模拟用户访问和管理员登录
threads = []
for i in range(7):
    if i % 2 == 0:
        t = threading.Thread(target=user_access, name=f"User {i}")
    else:
        t = threading.Thread(target=admin_login, name=f"Admin {i}")
    threads.append(t)
    t.start()

# 等待所有线程执行完毕
for t in threads:
    t.join()

实战案例

在真实的项目中,Semaphore的应用更为广泛。比如,在爬虫程序中,我们经常需要限制同时发起的请求数量,以避免给服务器带来过大压力。下面是一个使用Semaphore进行请求限流的例子:

import requests
import threading
from queue import Queue

# 创建一个初始值为5的Semaphore对象
semaphore = threading.Semaphore(5)

def fetch_url(url):
    semaphore.acquire()
    try:
        response = requests.get(url)
        print(f"访问 {url}: {response.status_code}")
    finally:
        semaphore.release()

# 初始化任务队列
urls = [
    "https://www.example.com",
    "https://www.google.com",
    "https://www.github.com",
    "https://www.python.org",
    "https://www.apache.org",
    "https://www.cnblogs.com",
    "https://www.baidu.com",
    "https://www.zhihu.com"
]
queue = Queue()
for url in urls:
    queue.put(url)

# 创建工作线程
def worker():
    while not queue.empty():
        url = queue.get()
        fetch_url(url)
        queue.task_done()

threads = []
for _ in range(8):
    t = threading.Thread(target=worker)
    threads.append(t)
    t.start()

# 等待所有线程执行完毕
for t in threads:
    t.join()

在这个例子中,我们首先定义了一个fetch_url函数来模拟网络请求。通过Semaphore的acquirerelease方法,我们成功地限制了同时发起的请求数量。此外,我们还使用了queue.Queue来管理待处理的任务列表,进一步提高了代码的可读性和可维护性。

扩展讨论

Semaphore虽然功能强大,但在使用过程中也存在一些需要注意的地方。例如,当一个线程调用release()方法时,如果没有其他线程等待该Semaphore,则该操作不会立即唤醒任何线程。此外,Semaphore并不提供公平性保证,即先等待的线程不一定能先获取许可。

对于更高级的需求,如优先级调度、定时许可等,Python提供了threading.Eventthreading.Condition等更强大的工具。了解这些工具的工作原理及其之间的区别,将有助于我们编写出更加高效、健壮的并发程序。

总之,Semaphore作为一种经典的同步原语,在并发编程中扮演着重要角色。通过本文的学习,希望你已经掌握了Semaphore的基本用法,并能够在自己的项目中灵活运用。当然,真正的精通还需要不断地实践与探索。希望你能在这个过程中发现更多乐趣!

标签:访问,Python,Semaphore,信号量,threading,线程,url,semaphore
From: https://blog.csdn.net/qq_44771627/article/details/142612933

相关文章

  • Python中的“锁”艺术:解锁Lock与RLock的秘密
    引言随着计算机性能的不断提升以及多核处理器的普及,多线程编程已成为现代软件开发不可或缺的一部分。然而,当多个线程试图同时修改同一份数据时,就可能会引发所谓的“竞态条件”(racecondition),即不同线程之间相互干扰导致程序行为不可预测。为了避免这种情况的发生,就需要引入......
  • 【2024版】最简单的Python安装 | Pycharm专业版激活码教程(新手小白都能学会)
    Python环境的安装1.下载安装程序:•打开浏览器,在Python官方网站上可以下载打包好的安装包在这里......
  • python+flask计算机毕业设计猫咪交流平台的设计与实现(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着现代生活节奏的加快,宠物已成为众多家庭不可或缺的一员,其中猫咪以其独立而又不失温柔的性格深受喜爱。然而,宠物主人之间往往缺乏有效的......
  • python+flask计算机毕业设计网络授课考勤系统(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着互联网技术的飞速发展,在线教育已成为教育领域的重要组成部分,尤其是在全球疫情背景下,网络授课更是成为了保障教育连续性的关键手段。然......
  • python处理英语发音音频的项目
    项目需求是这样的:想要获取单词的发音音频,词性,解释,音标,拆分单音标,根据发音拆分音节。实现思路:1、如果是批量处理的话,提前准备好需要处理的单词词库(全是要处理的单词)。2、通过API(你们懂得)可以获取到单词的  词性,解释,发音音频,保存到数据库中,测试单词:conversation3、处......
  • python+flask计算机毕业设计专业课在线自评自测系统的设计与实现(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着互联网技术的飞速发展和教育信息化的不断推进,传统教学模式正逐步向线上线下融合的新模式转变。在这一背景下,专业课程的学习与评估方式......
  • python+flask计算机毕业设计理财管理系统设计与实现(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着经济的快速发展和居民收入水平的提升,个人理财已成为现代生活中不可或缺的一部分。传统的手工记账方式已难以满足人们日益增长的理财需......
  • python+flask计算机毕业设计校园电子商品销售系统(程序+开题+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展和互联网的普及,电子商务已成为现代商业活动不可或缺的一部分,深刻改变着人们的消费习惯。在校园环境中,学生群体作为......
  • 基于python框架实现一个简化的trm
    基于py框架实现一个简化的trm?目录基于py框架实现一个简化的trm?词向量A1回顾A2引入模型(对比)A3DUNE --举例ini化独热前向传播反向传播1.ELMo(EmbeddingsfromLanguageModels)2.Transformer3.GPT(GenerativePre-trainedTransformer)4.BERT(BidirectionalEncoderRepresentations......
  • python requests模块学习
    1、模块介绍Pythonrequests是一个常用的HTTP请求库,可以方便地向网站发送HTTP请求,并获取响应结果。2、get请求示例#导入requests包importrequests#发送请求x=requests.get('https://www.run.com/')#返回http的状态码print(x.status_code)#获取响应......