广告
返回顶部
首页 > 资讯 > 后端开发 > Python >python 协程并发数控制
  • 486
分享到

python 协程并发数控制

2024-04-02 19:04:59 486人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

目录多线程之信号量协程中使用信号量控制并发aioHttp 中 tcpConnector 连接池前言: 本篇博客要采集的站点:【看历史,通天下-历史剧网】 目标数据是该站点下的热门历史

前言:

本篇博客要采集的站点:【看历史,通天下-历史剧网】

目标数据是该站点下的热门历史事件,列表页分页规则如下所示:

http://www.lishiju.net/hotevents/p0
http://www.lishiju.net/hotevents/p1
http://www.lishiju.net/hotevents/p2

首先我们通过普通的多线程,对该数据进行采集,由于本文主要目的是学习如何控制并发数,所以每页仅输出历史事件的标题内容。

普通的多线程代码:

import threading
import time
import requests
from bs4 import BeautifulSoup
class MyThread(threading.Thread):
    def __init__(self, url):
        threading.Thread.__init__(self)
        self.__url = url
    def run(self):
        res = requests.get(url=self.__url)
        soup = BeautifulSoup(res.text, 'html.parser')
        title_tags = soup.find_all(attrs={'class': 'item-title'})
        event_names = [item.a.text for item in title_tags]
        print(event_names)
        print("")
if __name__ == "__main__":
    start_time = time.perf_counter()
    threads = []
    for i in range(111):  # 创建了110个线程。
        threads.append(MyThread(url="http://www.lishiju.net/hotevents/p{}".fORMat(i)))
    for t in threads:
        t.start()  # 启动了110个线程。
    for t in threads:
        t.join()  # 等待线程结束
    print("累计耗时:", time.perf_counter() - start_time)
    # 累计耗时: 1.537718624

上述代码同时开启所有线程,累计耗时 1.5 秒,程序采集结束。

多线程之信号量

python 信号量(Semaphore)用来控制线程并发数,信号量管理一个内置的计数器。 信号量对象每次调用其 acquire()方法时,信号量计数器执行 -1 操作,调用 release()方法,计数器执行 +1 操作,当计数器等于 0 时,acquire()方法会阻塞线程,一直等到其它线程调用 release()后,计数器重新 +1,线程的阻塞才会解除。

使用 threading.Semaphore()创建一个信号量对象。

修改上述并发代码:

import threading
import time
import requests
from bs4 import BeautifulSoup
class MyThread(threading.Thread):
    def __init__(self, url):
        threading.Thread.__init__(self)
        self.__url = url
    def run(self):
        if semaphore.acquire():  # 计数器 -1
            print("正在采集:", self.__url)
            res = requests.get(url=self.__url)
            soup = BeautifulSoup(res.text, 'html.parser')
            title_tags = soup.find_all(attrs={'class': 'item-title'})
            event_names = [item.a.text for item in title_tags]
            print(event_names)
            print("")
            semaphore.release()  # 计数器 +1
if __name__ == "__main__":
    semaphore = threading.Semaphore(5)  # 控制每次最多执行 5 个线程
    start_time = time.perf_counter()
    threads = []
    for i in range(111):  # 创建了110个线程。
        threads.append(MyThread(url="http://www.lishiju.net/hotevents/p{}".format(i)))
    for t in threads:
        t.start()  # 启动了110个线程。
    for t in threads:
        t.join()  # 等待线程结束
    print("累计耗时:", time.perf_counter() - start_time)
    # 累计耗时: 2.8005530640000003

当控制并发线程数量之后,累计耗时变多。

补充知识点之 GIL:

GILPython 里面的全局解释器(互斥锁),在同一进程,同一时间下,只能运行一个线程,这就导致了同一个进程下多个线程,只能实现并发而不能实现并行

需要注意 python 语言并没有全局解释锁,只是因为历史的原因,在 CPython解析器中,无法移除 GIL,所以使用 CPython解析器,是会受到互斥锁影响的。

还有一点是在编写爬虫程序时,多线程比单线程性能是有所提升的,因为遇到 I/O 阻塞会自动释放 GIL锁。

协程中使用信号量控制并发

下面将信号量管理并发数,应用到协程代码中,在正式编写前,使用协程写法重构上述代码。

import time
import asyncio
import aiohttp
from bs4 import BeautifulSoup
async def get_title(url):
    print("正在采集:", url)
    async with aiohttp.request('GET', url) as res:
        html = await res.text()
        soup = BeautifulSoup(html, 'html.parser')
        title_tags = soup.find_all(attrs={'class': 'item-title'})
        event_names = [item.a.text for item in title_tags]
        print(event_names)
async def main():
    tasks = [asyncio.ensure_future(get_title("http://www.lishiju.net/hotevents/p{}".format(i))) for i in range(111)]
    dones, pendings = await asyncio.wait(tasks)
    # for task in dones:
    #     print(len(task.result()))
if __name__ == '__main__':
    start_time = time.perf_counter()
    asyncio.run(main())
    print("代码运行时间为:", time.perf_counter() - start_time)
    # 代码运行时间为: 1.6422313430000002

代码一次性并发 110 个协程,耗时 1.6 秒执行完毕,接下来就对上述代码,增加信号量管理代码。

核心代码是 semaphore = asyncio.Semaphore(10),控制事件循环中并发的协程数量。

import time
import asyncio
import aiohttp
from bs4 import BeautifulSoup
async def get_title(semaphore, url):
    async with semaphore:
        print("正在采集:", url)
        async with aiohttp.request('GET', url) as res:
            html = await res.text()
            soup = BeautifulSoup(html, 'html.parser')
            title_tags = soup.find_all(attrs={'class': 'item-title'})
            event_names = [item.a.text for item in title_tags]
            print(event_names)
async def main():
    semaphore = asyncio.Semaphore(10)  # 控制每次最多执行 10 个线程
    tasks = [asyncio.ensure_future(get_title(semaphore, "http://www.lishiju.net/hotevents/p{}".format(i))) for i in
             range(111)]
    dones, pendings = await asyncio.wait(tasks)
    # for task in dones:
    #     print(len(task.result()))
if __name__ == '__main__':
    start_time = time.perf_counter()
    asyncio.run(main())
    print("代码运行时间为:", time.perf_counter() - start_time)
    # 代码运行时间为: 2.227831242

aiohttp 中 TCPConnector 连接池

既然上述代码已经用到了 aiohttp 模块,该模块下通过限制同时连接数,也可以控制线程并发数量,不过这个不是很好验证,所以从数据上进行验证,先设置控制并发数为 2,测试代码运行时间为 5.56 秒,然后修改并发数为 10,得到的时间为 1.4 秒,与协程信号量控制并发数得到的时间一致。所以使用 TCPConnector 连接池控制并发数也是有效的。

import time
import asyncio
import aiohttp
from bs4 import BeautifulSoup
async def get_title(session, url):
    async with session.get(url) as res:
        print("正在采集:", url)
        html = await res.text()
        soup = BeautifulSoup(html, 'html.parser')
        title_tags = soup.find_all(attrs={'class': 'item-title'})
        event_names = [item.a.text for item in title_tags]
        print(event_names)
async def main():
    connector = aiohttp.TCPConnector(limit=1)  # 限制同时连接数
    async with aiohttp.ClientSession(connector=connector) as session:
        tasks = [asyncio.ensure_future(get_title(session, "http://www.lishiju.net/hotevents/p{}".format(i))) for i in
                 range(111)]
        await asyncio.wait(tasks)
if __name__ == '__main__':
    start_time = time.perf_counter()
    asyncio.run(main())
    print("代码运行时间为:", time.perf_counter() - start_time)

到此这篇关于python 协程并发数控制的文章就介绍到这了,更多相关python 协程内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: python 协程并发数控制

本文链接: https://www.lsjlt.com/news/118037.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • python 协程并发数控制
    目录多线程之信号量协程中使用信号量控制并发aiohttp 中 TCPConnector 连接池前言: 本篇博客要采集的站点:【看历史,通天下-历史剧网】 目标数据是该站点下的热门历史...
    99+
    2022-11-11
  • python并发之协程
    概念 协程,又称微线程。英文名Coroutine。 子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在执行过程中又调用了C,C执行完毕返回,B执行完毕返回,最后是A执行完毕。所以子程序调用是通过栈实现的,一个线程...
    99+
    2023-01-31
    python
  • Python并发编程之协程
    协程介绍 协程:是单线程下的并发,又称微线程,纤程。协程是一种用户态的轻量级线程,即线程是由用户程序自己控制调度的。 需要强调的是: #1. python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到io或执行时间过长就会被迫...
    99+
    2023-01-30
    Python
  • JMeter 控制并发数
    文章目录 一、误区二、正确设置 JMeter 的并发数总结 没用过 JMeter 的同学,可以先过一遍他的简单使用例子 https://blog.csdn.net/weixin_42132143/article/detai...
    99+
    2023-08-18
    jmeter java 开发语言
  • Python控制多进程与多线程并发数总结
    一、前言 本来写了脚本用于暴力破解密码,可是1秒钟尝试一个密码2220000个密码我的天,想用多线程可是只会一个for全开,难道开2220000个线程吗?只好学习控制线程数了,官方文档不好看,觉得结构不够...
    99+
    2022-06-04
    多线程 进程 Python
  • golang怎么控制并发数
    在Go中,可以使用goroutine和channel来控制并发数。 首先,可以使用make函数创建一个带有指定并发数的channel...
    99+
    2023-10-21
    golang
  • MySQL并发控制
    介绍 无论何时,只要有多个查询需要在同一时刻修改数据,都会产生并发控制的问题。而这种并发问题的直接后果就是数据不一致问题。那么如何解决这种问题呢?MySQL需要采用锁定机制来解决。 MySQL数据库由于其自身架构的特点,存在多种数据存储引擎...
    99+
    2019-07-16
    MySQL并发控制
  • 关于python并发编程中的协程
    目录什么是协程协程和线程协程的应用演示Demo什么是协程 协程(Coroutine)是一种比线程更加轻量级的并发方式,它不需要线程上下文切换的开销,可以在单线程中实现并发。协程通常具...
    99+
    2023-05-17
    python 并发编程 python 协程
  • go语言限制协程并发数的方案详情
    目录前言一、使用带缓冲的通道限制并发数1.1方案详情1.2评估总结2.2评估总结其它前言 在使用协程并发处理某些任务时, 其并发数量往往因为各种因素的限制不能无限的增大. 例如网络请...
    99+
    2022-11-13
  • golang怎么控制并发数量
    在Go语言中,可以使用goroutine和channel来控制并发数量。 首先,可以使用goroutine来并发执行任务。例如,有一...
    99+
    2023-10-26
    golang
  • 掌控MySQL并发:深度解析锁机制与并发控制
    前一篇MySQL读取的记录和我想象的不一致——事物隔离级别和MVCC 讲了事务在并发执行时可能引发的一致性问题的各种现象。一般分为下面3种情况: 读 - 读情况:并发事务相继读取相同的记录。读取...
    99+
    2023-09-18
    MySQL并发控制 隐式锁 插入意向锁 行锁 表锁
  • Java并发编程(03):多线程并发访问,同步控制
    本文源码:GitHub·点这里 || GitEE·点这里一、并发问题多线程学习的时候,要面对的第一个复杂问题就是,并发模式下变量的访问,如果不理清楚内在流程和原因,经常会出现这样一个问题:线程处理后的变量值不是自己想要的,可能还会一脸懵的...
    99+
    2023-06-02
  • Go 并发编程协程及调度机制详情
    目录协程的概念goroutine 的诞生使用 goroutine 加快速度goroutine 的机制原理前言: 协程(coroutine)是 Go 语言最大的特色之一,gorouti...
    99+
    2022-11-11
  • golang控制并发数怎么实现
    在Go语言中,可以使用goroutine和channel来实现并发控制。下面是一种常见的实现方式: 创建一个有缓冲的channel...
    99+
    2023-10-21
    golang
  • Linux中Shell多进程并发以及并发数控制的示例分析
    这篇文章主要介绍了Linux中Shell多进程并发以及并发数控制的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1. 基础知识准备1. linux后台进程Unix是一...
    99+
    2023-06-10
  • python3通过gevent.pool限制协程并发数量的实现方法
    协程虽然是轻量级的线程,但到达一定数量后,仍然会造成服务器崩溃出错。最好的方法通过限制协程并发数量来解决此类问题。 server代码: #!/usr/bin/env python...
    99+
    2022-11-12
  • python实现多进程并发控制Semaphore与互斥锁LOCK
    一、了解锁 应用场景举例描述: Lock 互斥锁:举例说明有三个同事同时需要上厕所,但是只有一间厕所,将同事比作进程,多个进程并打抢占一个厕所,我们要保证顺序优先, 一个个来,那么就必须串行,先到先得,有人使用了,...
    99+
    2022-06-02
    python 多进程Semaphore与LOCK python 多进程并发控制Semaphore Python互斥锁LOCK
  • golang的最大并发数怎么控制
    在Golang中,可以通过控制goroutine的数量来控制最大并发数。 一种常见的方法是使用带有缓冲的channel来限制并发数。...
    99+
    2023-10-21
    golang
  • 怎么浅析数据库并发控制
    怎么浅析数据库并发控制,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。数据库事务隔离发展标准一文中,从标准制定的角度介绍了数据库的隔离级别,介绍...
    99+
    2022-10-19
  • js Promise并发控制数量的方法
    目录问题背景思路 & 实现问题 要求写一个方法控制 Promise 并发数量,如下: promiseConcurrencyLimit(limit, array, ite...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作