Python使用select模块/asyncio库实现轮询机制

news2024/10/5 22:21:22

一、轮询机制概念

在操作系统中,用户态轮询机制是一种等待系统中某个资源就绪的方式,它通常用于非阻塞式I/O操作。这种机制允许用户进程在等待I/O操作完成时继续执行其他任务,而不是一直阻塞等待。用户进程可以使用系统调用将I/O操作请求提交到内核,然后轮询(通过反复检查状态)该请求是否完成。

在用户态轮询机制中,用户进程使用非阻塞式I/O操作来提交请求,然后在请求完成前反复检查请求的状态是否已经就绪。如果请求还未完成,则继续执行其他任务,一旦请求完成,则返回操作系统,并从内核中读取数据。此时,用户进程再次运行,并在需要时再次提交新的I/O请求。

用户态轮询机制的优点在于可以提高系统的吞吐量,因为不需要等待I/O操作完成,可以先执行其他任务。此外,它也可以帮助避免阻塞,从而提高系统的响应能力,因为用户进程可以在I/O操作等待期间继续执行其他任务。但是,它也会消耗更多的CPU时间,因为用户进程需要不断检查I/O请求的状态。

二、Python实现轮询机制

在Python中,实现轮询机制可以使用select模块或更高级别的asyncio库。

使用select模块:

server

[root@localhost python]# cat selectTCP.py 
import select
import socket

host = "192.168.6.211"
port = 8888
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host, port))
server.listen(10)
inputs = [server]

while True:
    ready_for_reading, _, _ = select.select(inputs, [], [])
    for sock in ready_for_reading:
        if sock == server:
            # 如果是server socket,表示有新的客户端连接请求
            client, address = server.accept()
            inputs.append(client)
        else:
            # 如果是client socket,表示有数据可读
            data = sock.recv(1024)
            if data:
                # 处理数据
                print(data)
            else:
                # 关闭socket
                inputs.remove(sock)
                sock.close()

[root@localhost python]# cat tcp_clientTrue.py 
import socket

HOST = '192.168.6.211'
PORT = 8888

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((HOST, PORT))

message = 'Hello from client!'
client_socket.send(message.encode('utf-8'))

response = client_socket.recv(1024).decode('utf-8')
print(f'Received response from server: {response}')

client_socket.close()

以上示例程序使用select模块实现了一个简单的TCP服务器。在主循环中,程序调用select.select()方法来等待socket的读就绪事件。如果是server socket,表示有新的客户端连接请求;如果是client socket,表示有数据可读。

使用asyncio库:

import asyncio
import socket

host = "192.168.6.1"
port = 8888

async def handle_client(reader, writer):
    while True:
        data = await reader.read(1024)
        if not data:
            # 关闭流
            writer.close()
            break
        # 处理数据
        print(data)

async def run_server():
    # server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # server.bind((host, port))
    # server.listen(10)
    # server.setblocking(False)

    # while True:
    #     client, address = await asyncio.start_server(handle_client, host, port)
    #     asyncio.create_task(handle_client(client))
    server = await asyncio.start_server(handle_client, host, port)
    async with server:
        await server.serve_forever()

asyncio.run(run_server())
[root@localhost python]# cat tcp_clientPC.py 
import socket

HOST = '192.168.6.1'
PORT = 8888

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((HOST, PORT))

message = 'Hello from client!'
client_socket.send(message.encode('utf-8'))

response = client_socket.recv(1024).decode('utf-8')
print(f'Received response from server: {response}')

client_socket.close()

以上示例程序使用asyncio库实现了一个简单的TCP服务器。在主循环中,程序调用asyncio.sock_accept()方法来异步等待客户端连接请求。一旦有客户端连接上,程序创建一个任务来处理客户端数据的读取和处理。在任务中,使用asyncio.sock_recv()方法来异步等待客户端数据的读取。如果没有数据,则关闭socket。

附:报错说明

报错一:

AttributeError: module 'asyncio' has no attribute 'sock_accept'

这个错误可能是因为在Python 3.8及之后的版本中,asyncio模块中的sock_accept方法已经被废弃。可以改用asyncio.start_server()方法来实现异步监听客户端连接请求,并在有新连接时调用回调函数处理客户端数据。

以下是一个使用asyncio.start_server()方法实现的简单TCP服务器示例:

import asyncio
import socket

host = "localhost"
port = 5000

async def handle_client(reader, writer):
    while True:
        data = await reader.read(1024)
        if not data:
            # 关闭流
            writer.close()
            break
        # 处理数据
        pass

async def run_server():
    server = await asyncio.start_server(handle_client, host, port)
    async with server:
        await server.serve_forever()

asyncio.run(run_server())

在上面的示例中,asyncio.start_server()方法会异步监听客户端连接请求,并在有新连接时自动调用handle_client()方法来处理客户端数据。在handle_client()方法内部,代码使用await reader.read()方法来异步等待客户端数据的读取。如果没有数据,则关闭流。asyncio库自动管理流的关闭,因此不需要手动关闭。最后,使用await server.serve_forever()方法来使服务器一直运行下去。

报错二:

ValueError: Neither host/port nor sock were specified

这个错误通常是因为在使用asyncio.start_server()方法时,没有正确指定hostport参数。

以下是一个使用asyncio.start_server()方法实现的简单TCP服务器示例,其中正确指定了hostport参数:

import asyncio

async def handle_client(reader, writer):
    while True:
        data = await reader.read(1024)
        if not data:
            # 关闭流
            writer.close()
            break
        # 处理数据
        pass

async def run_server():
    host = "localhost"
    port = 5000
    server = await asyncio.start_server(handle_client, host, port)
    async with server:
        await server.serve_forever()

asyncio.run(run_server())

在上面的示例中,hostport参数被正确指定为"localhost"5000,因此不会出现ValueError: Neither host/port nor sock were specified的错误。

报错三:

OSError: [Errno 10048] error while attempting to bind on address ('127.0.0.1', 8888): 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。

这个错误通常是因为在使用asyncio.start_server()方法时,指定的端口已经被占用了。

解决这个问题最简单的方法是使用一个没有被占用的端口。另外,也可以通过以下两种方法解决这个问题:

  1. 关闭占用端口的程序或服务:使用lsof -i :端口号命令查看占用该端口的程序或服务,然后结束该程序或服务;
  2. 修改使用的端口号:可以使用一个未被占用的端口号替换原来的端口号。

以下是一个修改端口号的示例:

import asyncio

async def handle_client(reader, writer):
    while True:
        data = await reader.read(1024)
        if not data:
            # 关闭流
            writer.close()
            break
        # 处理数据
        pass

async def run_server():
    host = "localhost"
    port = 8889  # 修改为未被占用的端口号
    server = await asyncio.start_server(handle_client, host, port)
    async with server:
        await server.serve_forever()

asyncio.run(run_server())

在上面的示例中,我们将端口号从8888修改为8889,可以避免OSError: [Errno 10048] error while attempting to bind on address ('127.0.0.1', 8888): 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。错误的发生。

报错四:

AttributeError: module 'asyncio' has no attribute 'run'

asyncio.run()是在Python 3.7中引入的新方法,用于运行一个async函数。如果在较早的Python版本中使用asyncio.run()方法,则会出现AttributeError: module 'asyncio' has no attribute 'run'错误。

要解决这个问题,可以采用以下两种方法之一:

  1. 将Python版本升级到3.7或更高版本,以便使用asyncio.run()方法。
  2. 在较早的Python版本中,使用asyncio.get_event_loop().run_until_complete()方法来运行async函数。

以下是使用第二种方法修改的示例代码:

import asyncio

async def main():
    # 你的async方法代码

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

在上面的示例中,我们使用asyncio.get_event_loop().run_until_complete()方法来运行main()async函数,而不是使用asyncio.run()方法。这将解决AttributeError: module 'asyncio' has no attribute 'run'错误。

报错五:

    async with server:
AttributeError: __aexit__

这个错误通常发生在使用一个不支持上下文管理器的对象时,而Python中的async with语法需要对象支持上下文管理器。因此,解决这个问题的方法是检查使用的对象是否支持上下文管理器。

如果使用的对象本身不支持上下文管理器,可以考虑使用其他方法来替代async with语法。例如,使用asyncio.ensure_future()asyncio.create_task()来运行异步任务,这两个方法都不需要上下文管理器。

如果对象本身支持上下文管理器,但是出现了__aexit__属性缺失的错误,那么可能是因为使用的是Python 3.6及以下版本。在这些版本中,async with语法不支持异步上下文管理器。要解决这个问题,可以考虑升级Python版本或者使用其他方法来实现异步上下文管理器,例如使用async_generator库提供的asynccontextmanager装饰器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/768270.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数学分析:换元详解

这一端文章没有写详细的证明。意思是说n维空间下的k个向量围成的多面体的体积,都可以用公式(3)进行计算。详细证明过程参考:行列式的一种推广 - 知乎 这里简述下过程: 首先要把这n个m维向量进行格拉姆斯密特正交化,得到正交后的…

解决appium-doctor报gst-launch-1.0.exe and/or gst-inspect-1.0.exe cannot be found

一、下载gst-launch-1.0.exe and gst-inspect-1.0.exe 下载地址:Download GStreamer runtime installer 和 development installer 两个应用程序都要下载并安装 二、运行安装 下载好后点击安装会弹出如下界面,点击“更多信息”展开,点击“仍然…

C语言实现计算器简单混合运算

计算器的实现看似简单,其实并不简单。 要求完成功能: 1.实现 - * / 简单运算; 2.可以实现这几个运算符的综合(混合)运算; 注意:该计算器混合运算中不包含太复杂的运算符,如()&am…

星戈瑞 CY3-Dextran的合成方法和表征

CY3-Dextran是一种荧光染料,可用于细胞标记和显微镜观察。它具有很强的荧光信号和稳定性,可以用于研究细胞生物学和分子生物学。 CY3-Dextran的合成方法涉及将CY3染料与葡聚糖进行共价结合。以下是一种常用的合成方法: 【合成方法】&#xf…

3.1例子---登录窗口1

3.1例子—登录窗口1 这一次效果图是这样的: 界面创建 # welcome image canvas tk.Canvas(window, height200, width500)#创建画布 image_file tk.PhotoImage(filewelcome.gif)#加载图片文件 image canvas.create_image(0,0, anchornw, imageimage_file)#将图…

MySQL数据库第九课--------join连接四件套------不错的哦哦哦

作者前言 欢迎小可爱们前来借鉴我的gtiee秦老大大 (qin-laoda) - Gitee.com ____________________________________________________________________ 目录 SQL查询语句 限定输出 limit 连接查询 join 内连接 左连接 右连接 外连接 ____________________________________…

xxx.indexOf is not a function报错

注意:xxx 如果是数字、布尔、对象,然而indexOf用于查找字符串或数组中的元素,所以会报错。

Qt5.15.2安装

解释一下 Qt 的版本号 比如 5.15.2 是完整的 Qt 版本号,第一个数字 5 是大版本号(major),第二个数字 15 是小版本号(minor),第三个数字 2 是补丁号(patch)。 只要前面两个…

Python异步编程框架Tornado使用方法

Tornado简介 Python异步编程框架Tornado是一个轻量级的Web框架和异步网络库,它能够处理大量并发连接和请求,非常适合高并发的网络应用和实时应用。 Tornado基本概念: 协程:Tornado采用协程并发模型,可以让单线程同时…

Vue第三篇:最简单的vue购物车示例

本文参考&#xff1a;Vue Cli&#xff08;脚手架&#xff09;实现购物车小案例 - - php中文网博客 效果图&#xff1a; 编写流程&#xff1a; 1、首先通过vue/cli创建工程 vue create totalprice 2、改写App.vue代码如下&#xff1a; <template><div><div v…

017 - STM32学习笔记 - SPI读写FLASH(二)

016 - STM32学习笔记 - SPI访问Flash&#xff08;二&#xff09; 上节内容学习了通过SPI读取FLASH的JEDEC_ID&#xff0c;在flash资料的指令表中&#xff0c;还看到有很多指令可以使用&#xff0c;这节继续学习使用其他指令&#xff0c;程序模板采用上节的模板。 为了方便起…

uni-app中a标签下载文件跳转后左上角默认返回键无法继续返回

1.首先使用的是onBackPress //跟onShow同级别 onBackPress(option){ uni.switchTab({ url:/pages/....... return true }) }发现其在uni默认头部中使用是可以的 但是h5使用了"navigationStyle":"custom"后手机默认的返回并不可以&#xff0c; 2.经过查询…

autok3s k3d rancher研究

参考 功能介绍 | Rancher文档AutoK3s 是用于简化 K3s 集群管理的轻量级工具&#xff0c;您可以使用 AutoK3s 在任何地方运行 K3s 服务。http://docs.rancher.cn/docs/k3s/autok3s/_index 什么是 AutoK3s k3s是经过完全认证的 Kubernetes 产品&#xff0c;在某些情况下可以替…

Centos 7 使用国内镜像源更新内核

内核选择参考 此博文 &#xff1a;https://blog.csdn.net/alwaysbefine/article/details/108931626 elrepo官网介绍的内核升级方式为&#xff1a; 一、按文档执行引入 elrepo库&#xff1b; # 1、引入公钥 rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org# 2、安…

数据中心水浸事件,该如何找回安全?

数据中心是现代企业和组织中不可或缺的基础设施&#xff0c;承载着大量的敏感数据和关键业务运作。然而&#xff0c;水浸事件可能成为数据中心的巨大威胁&#xff0c;可能导致设备故障、数据丢失以及业务中断&#xff0c;给组织带来严重的损失和风险。 因此&#xff0c;为了保护…

机器学习(十六):决策树

全文共18000余字&#xff0c;预计阅读时间约36~60分钟 | 满满干货&#xff0c;建议收藏&#xff01; 一、介绍 树模型是目前机器学习领域最为重要的模型之一&#xff0c;同时它也是集成学习中最常用的基础分类器。 与线性回归、逻辑回归等算法不同&#xff0c;树模型并不只是…

力扣707设计链表

你可以选择使用单链表或者双链表&#xff0c;设计并实现自己的链表。 单链表中的节点应该具备两个属性&#xff1a;val 和 next 。val 是当前节点的值&#xff0c;next 是指向下一个节点的指针/引用。 如果是双向链表&#xff0c;则还需要属性 prev 以指示链表中的上一个节点…

Spring Security OAuth2.0(5):Spring Security工作原理

文章目录 工作原理结构总览 认证流程授权流程AuthenticationProviderUserDetailsServicePasswordEncoder如何使用BCryptPasswordEncoder 授权流程授权流程授权决策 工作原理 结构总览 \qquad Spring Security 所解决的问题就是安全访问控制&#xff0c;而安全访问控制功能其实…

3.12 Bootstrap 超大屏幕(Jumbotron)

文章目录 Bootstrap 超大屏幕&#xff08;Jumbotron&#xff09; Bootstrap 超大屏幕&#xff08;Jumbotron&#xff09; 下面将讲解 Bootstrap 支持的另一个特性&#xff0c;超大屏幕&#xff08;Jumbotron&#xff09;。顾名思义该组件可以增加标题的大小&#xff0c;并为登陆…

MySQL-多表设计-一对一多对多

一对一 案例&#xff1a;用户 与身份证信息 的关系关系&#xff1a;一对一关系&#xff0c;多用于单表拆分&#xff0c;将一张表的基础字段放在一张表中&#xff0c;其它字段放在另一张表中&#xff0c;以提高操作效率实现&#xff1a;在任意一方加入外键&#xff0c;关联另一…