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

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

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

問題復現(xiàn)

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

寫一個小 dome 復現(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 有關,那什么是 select 呢?要怎么解決呢?別急,我們首先來了解一下 asyncio 中的事件循環(huán),即 EventLoop。

事件循環(huán) EventLoop

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

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

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

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

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

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

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

import asyncio

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

  • Linux:

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

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

I/O 多路復用

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

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

select 的缺點

I/O 多路復用這個概念被提出來以后, select 是第一個實現(xiàn)這個概念的,select 被實現(xiàn)以后,很快就暴露出了很多問題,其中一個缺點就是 select 在 Windows 中限制了文件描述符數(shù)量為 512 個,在 Linux 中限制為 1024 個,那么在前面的 dome 中,使用的是 Python 3.5,這個版本的 asyncio 默認使用了 SelectorEventLoop,底層調用的是 select,受 select 缺點的影響,并發(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 管理一個內部計數(shù)器,該計數(shù)器在每次調用 acquire() 方法時遞減,每次調用 release() 方法時遞增,計數(shù)器永遠不會低于零,當方法 acquire() 發(fā)現(xiàn)它為零時,它會阻塞,等待其他線程調用 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 任務
    return task


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

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

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

Linux

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

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

ulimit 命令參考:

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

總結

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

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

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

Windows

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

Linux

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

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

相關文章

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

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

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

    python運行cmd命令行的3種方法總結

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

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

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

    python調用api實例講解

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

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

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

    Python socket非阻塞模塊應用示例

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

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

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

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

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

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

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

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

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

最新評論