欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python解決asyncio文件描述符最大數(shù)量限制的問題

 更新時間:2024年06月27日 10:30:25   作者:IT.BOB  
這篇文章主要介紹了Python解決asyncio文件描述符最大數(shù)量限制的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

問題復(fù)現(xiàn)

Windows 平臺下,Python 版本 3.5,使用異步框架 asyncio,有時候會出現(xiàn) ValueError: too many file descriptors in select() 的報錯信息,我們就來聊一下為什么會出現(xiàn)這種問題,以及問題的一些解決方法。

寫一個小 dome 復(fù)現(xiàn)這個問題(環(huán)境:Windows 64 位、Python 3.7):

import aiohttp
import asyncio


num = 0


async def main(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            global num
            num += 1
            print('%s ——> %s' % (str(num), response.status))


def tasks():
    url = 'https://www.baidu.com/s?ie=UTF-8&wd=%s'
    task = [main(url % i) for i in range(10000)]
    return task


loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks()))

在打印 500 次左右后就會出現(xiàn)以下報錯:

問題分析

好像這個報錯和 select 有關(guān),那什么是 select 呢?要怎么解決呢?別急,我們首先來了解一下 asyncio 中的事件循環(huán),即 EventLoop。

事件循環(huán) EventLoop

事件循環(huán)是 asyncio 的核心,異步任務(wù)的運(yùn)行、任務(wù)完成之后的回調(diào)、網(wǎng)絡(luò) I/O 操作、子進(jìn)程的運(yùn)行,都是通過事件循環(huán)完成的,通俗來講,事件循環(huán)所做的就是等待事件發(fā)生,然后再將每個事件與我們已明確與所述事件類型匹配的函數(shù)進(jìn)行匹配。

下圖很好的展示了協(xié)程、事件循環(huán)之間的相互作用:

在 asyncio 中,主要提供了兩種不同事件循環(huán)的實現(xiàn)方法:

  • SelectorEventLoop:基于 selectors 模塊的事件循環(huán),selectors 又是建立在底層的 I/O 復(fù)用模塊 select 之上的,selectors 提供了高度封裝和高效的 I/O 復(fù)用,也就是說 SelectorEventLoop 在底層就是使用了 select I/O 多路復(fù)用的機(jī)制。
  • ProactorEventLoop:使用 IOCP 專為 Windows 構(gòu)建的事件循環(huán),IOCP 全稱 I/O Completion Port,即 I/O 完成端口。它是支持多個同時發(fā)生的異步 I/O 操作的應(yīng)用程序編程接口,它充分利用內(nèi)核對象的調(diào)度,只使用少量的幾個線程來處理和客戶端的所有通信,消除了無謂的線程上下文切換,是 Windows 下性能最好的 I/O 模型,有關(guān) IOCP 的詳細(xì)介紹可參考微軟文檔。

那么這兩種方法有什么區(qū)別呢?在 asyncio 中什么時候用什么方法呢?

我們不妨看一下 asyncio 的源碼,在 Python 3.7 中,無論在 Windows 還是 Linux 中都可以看到其默認(rèn)的設(shè)置是 SelectorEventLoop:

我們也可以分別在 Windows 平臺和 Linux 平臺打印一下 EventLoop 對象(Python 3.7),可以看到默認(rèn)都是 SelectorEventLoop:

import asyncio

loop = asyncio.get_event_loop()
print(loop)
  • Windows:

  • Linux:

事實上,在 Python 3.7 以及之前的版本中, 所有平臺默認(rèn)使用的都是 SelectorEventLoop,在 Python 3.8 以及以后的版本中,Unix 平臺默認(rèn)使用的是 SelectorEventLoop,Windows 平臺默認(rèn)使用的是 ProactorEventLoop,這個差異可以在官方文檔中看到。

說了這么多,這和 ValueError: too many file descriptors in select() 的報錯問題有什么關(guān)系呢?select 到底是什么東西呢?

I/O 多路復(fù)用

要了解 select,我們還要了解一下什么是 I/O 多路復(fù)用(I/O multiplexing),服務(wù)器端編程經(jīng)常需要構(gòu)造高性能的 I/O 模型,常見的 I/O 模型有同步阻塞 I/O、同步非阻塞 I/O、I/O 多路復(fù)用等;當(dāng)需要同時處理多個客戶端接入請求時,可以利用多線程或者 I/O 多路復(fù)用技術(shù)進(jìn)行處理,I/O 多路復(fù)用技術(shù)就是為了解決進(jìn)程或線程阻塞到某個 I/O 系統(tǒng)調(diào)用而出現(xiàn)的技術(shù),使進(jìn)程不阻塞于某個特定的 I/O 系統(tǒng)調(diào)用。

select,poll,epoll 等都是 I/O 多路復(fù)用的一種機(jī)制,其中后兩個在 Linux 中可用,Windows 僅支持 select,I/O 多路復(fù)用通過這種機(jī)制,可以監(jiān)視多個描述符,一旦某個描述符就緒,一般是讀就緒或者寫就緒,就是在這個文件描述符進(jìn)行讀寫操作之前,能夠通知程序進(jìn)行相應(yīng)的讀寫操作。

select 的缺點(diǎn)

I/O 多路復(fù)用這個概念被提出來以后, select 是第一個實現(xiàn)這個概念的,select 被實現(xiàn)以后,很快就暴露出了很多問題,其中一個缺點(diǎn)就是 select 在 Windows 中限制了文件描述符數(shù)量為 512 個,在 Linux 中限制為 1024 個,那么在前面的 dome 中,使用的是 Python 3.5,這個版本的 asyncio 默認(rèn)使用了 SelectorEventLoop,底層調(diào)用的是 select,受 select 缺點(diǎn)的影響,并發(fā)量過高,就出現(xiàn)了 ValueError: too many file descriptors in select() 的報錯信息。

解決方法

1.更換事件循環(huán)選擇器

如果你使用的是 Python 3.7 及以下的版本,那么在 Windows 平臺,可以使用 ProactorEventLoop。在 Linux 平臺可以使用 PollSelector。

注意:如果你使用了 ProactorEventLoop,那么你將無法使用代理!這是 asyncio 的 bug,早在 2020 年 1 月就有人提過 issue,目前仍然可以看到類似的 issue,官方貌似也還沒辦法解決,所以,如果您必須要使用代理,則可以參考后面的解決辦法。

import selectors
import asyncio
import sys

if sys.platform == 'win32':
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)
else:
    selector = selectors.PollSelector()
    loop = asyncio.SelectorEventLoop(selector)
    asyncio.set_event_loop(loop)

2.限制并發(fā)量

可以使用方法 asyncio.Semaphore() 來限制并發(fā)量,Semaphore 就是信號量的意思,Semaphore 管理一個內(nèi)部計數(shù)器,該計數(shù)器在每次調(diào)用 acquire() 方法時遞減,每次調(diào)用 release() 方法時遞增,計數(shù)器永遠(yuǎn)不會低于零,當(dāng)方法 acquire() 發(fā)現(xiàn)它為零時,它會阻塞,等待其他線程調(diào)用 release() 方法。

通過限制并發(fā)量的方法來解決報錯問題是個不錯的選擇。

import aiohttp
import asyncio


num = 0


async def main(url, semaphore):
    async with semaphore:
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as response:
                global num
                num += 1
                print('%s ——> %s' % (str(num), response.status))


def tasks():
    semaphore = asyncio.Semaphore(300)                         # 限制并發(fā)量為 300
    url = 'https://www.baidu.com/s?ie=UTF-8&wd=%s'
    task = [main(url % i, semaphore) for i in range(10000)]    # #總共 10000 任務(wù)
    return task


loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks()))

3.修改最大文件描述符限制Windows

在 Windows 中,最大文件描述符限制在 C 語言的頭文件 Winsock2.h 中使用變量 FD_SETSIZE 進(jìn)行定義,如果要修改它,可以通過在包含 Winsock2.h 之前將 FD_SETSIZE 定義為另一個值來修改,如果我們使用的編程語言是 Python 的話,是不太好對這個值進(jìn)行修改的,可以參考微軟官方文檔:https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-select

Linux

在 Linux 平臺,可以使用 ulimit 命令來修改最大文件描述符限制:

  • 查看當(dāng)前會話最大文件描述符限制(默認(rèn)1024):ulimit -n
  • 臨時修改限制,只對當(dāng)前的會話有效:ulimit -SHn 65536
  • 永久修改限制,在 /etc/security/limits.conf 文件里新增以下內(nèi)容:
* hard nofile 65536
* soft nofile 65536

ulimit 命令參考:

  • -S使用軟 (soft) 資源限制
  • -H使用硬 (hard) 資源限制
  • -a所有當(dāng)前限制都被報告
  • -b套接字緩存尺寸
  • -c創(chuàng)建的核文件的最大尺寸
  • -d一個進(jìn)程的數(shù)據(jù)區(qū)的最大尺寸
  • -e最高的調(diào)度優(yōu)先級 (nice)
  • -f有 shell 及其子進(jìn)程可以寫的最大文件尺寸
  • -i最多的可以掛起的信號數(shù)
  • -k分配給此進(jìn)程的最大 kqueue 數(shù)量
  • -l一個進(jìn)程可以鎖定的最大內(nèi)存尺寸
  • -m最大的內(nèi)存進(jìn)駐尺寸
  • -n最多的打開的文件描述符個數(shù)
  • -p管道緩沖區(qū)尺寸
  • -qPOSIX 信息隊列的最大字節(jié)數(shù)
  • -r實時調(diào)度的最大優(yōu)先級
  • -s最大棧尺寸
  • -t最大的CPU時間,以秒為單位
  • -u最大用戶進(jìn)程數(shù)
  • -v虛擬內(nèi)存尺寸
  • -x最大的文件鎖數(shù)量
  • -P最大偽終端數(shù)量
  • -T最大線程數(shù)量

總結(jié)

asyncio 事件循環(huán)選擇器,在 Python 3.7 以及之前的版本中,所有平臺默認(rèn)使用的都是 SelectorEventLoop,在 Python 3.8 以及以后的版本中,Unix 平臺默認(rèn)使用的是 SelectorEventLoop,Windows 平臺默認(rèn)使用的是 ProactorEventLoop。

select 在 Windows 中限制了文件描述符最大數(shù)量為 512 個,在 Linux 中限制為 1024 個。

要解決 ValueError: too many file descriptors in select() 的報錯問題,根據(jù)您的平臺和業(yè)務(wù)要求選擇合理的解決方法:

Windows

  • 通過 asyncio.Semaphore() 方法來限制并發(fā)量,通常設(shè)置在 300-500 比較合理,這是最優(yōu)的做法;
  • 更換 asyncio 的事件循環(huán)選擇器為 ProactorEventLoop,注意:這將導(dǎo)致無法使用代理!

Linux

  • 通過 asyncio.Semaphore() 方法來限制并發(fā)量,通常設(shè)置在 800-1000 比較合理;
  • 通過 ulimit 命令來修改最大文件描述符限制;
  • 更換 asyncio 的事件循環(huán)選擇器為 PollSelector。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • PyQt5 如何讓界面和邏輯分離的方法

    PyQt5 如何讓界面和邏輯分離的方法

    這篇文章主要介紹了PyQt5 如何讓界面和邏輯分離的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • python運(yùn)行cmd命令行的3種方法總結(jié)

    python運(yùn)行cmd命令行的3種方法總結(jié)

    雖然python在調(diào)用cmd命令方面使用的比較少,不過還是要用的,下面這篇文章主要給大家介紹了關(guān)于python運(yùn)行cmd命令行的3種方法,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-09-09
  • Python3中使用urllib的方法詳解(header,代理,超時,認(rèn)證,異常處理)

    Python3中使用urllib的方法詳解(header,代理,超時,認(rèn)證,異常處理)

    這篇文章整理了一些關(guān)于urllib使用中的一些關(guān)于header,代理,超時,認(rèn)證,異常處理處理方法,對大家學(xué)習(xí)python具有一定的參考借鑒價值,有需要的朋友們下面來一起看看吧。
    2016-09-09
  • python調(diào)用api實例講解

    python調(diào)用api實例講解

    在本篇內(nèi)容里小編給大家分享的是一篇關(guān)于python調(diào)用api實例講解內(nèi)容,有興趣的朋友們可以參考下。
    2021-04-04
  • Python3操作讀寫CSV文件使用包過程解析

    Python3操作讀寫CSV文件使用包過程解析

    這篇文章主要介紹了Python3操作CSV文件使用包過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04
  • Python socket非阻塞模塊應(yīng)用示例

    Python socket非阻塞模塊應(yīng)用示例

    這篇文章主要介紹了Python socket非阻塞模塊,結(jié)合實例形式分析了Python socket非阻塞模塊通信相關(guān)操作技巧,需要的朋友可以參考下
    2019-09-09
  • Python中使用ConfigParser解析ini配置文件實例

    Python中使用ConfigParser解析ini配置文件實例

    這篇文章主要介紹了Python中使用ConfigParser解析ini配置文件實例,本文給出了創(chuàng)建和讀取ini文件的例子,需要的朋友可以參考下
    2014-08-08
  • python機(jī)器學(xué)習(xí)實現(xiàn)神經(jīng)網(wǎng)絡(luò)示例解析

    python機(jī)器學(xué)習(xí)實現(xiàn)神經(jīng)網(wǎng)絡(luò)示例解析

    這篇文章主要為大家介紹了python機(jī)器學(xué)習(xí)python實現(xiàn)神經(jīng)網(wǎng)絡(luò)的示例解析,在同樣在進(jìn)行python機(jī)器學(xué)習(xí)的同學(xué)可以借鑒參考下,希望能夠有所幫助
    2021-10-10
  • Python 京東云無線寶消息推送功能

    Python 京東云無線寶消息推送功能

    這篇文章主要介紹了Python 京東云無線寶消息推送功能,發(fā)送釘釘消息獲取可用積分,詳細(xì)配置文件通過實例代碼給大家講解的很詳細(xì),代碼+注釋講解的很詳細(xì),需要的朋友可以參考下
    2021-05-05
  • Pytorch神經(jīng)網(wǎng)絡(luò)參數(shù)管理方法詳細(xì)講解

    Pytorch神經(jīng)網(wǎng)絡(luò)參數(shù)管理方法詳細(xì)講解

    這篇文章主要介紹了Pytorch神經(jīng)網(wǎng)絡(luò)參數(shù)管理方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-05-05

最新評論