纯Python非阻塞IO函数
项目描述
非阻塞python IO函数
这些是纯Python函数,可以在Python中执行非阻塞I/O。
nonblock_read
nonblock_read提供了以非阻塞方式读取缓冲区(如文件、管道或套接字)上可用的任何内容的能力。如readline等方法将阻塞直到打印出换行符等。
您可以提供一个限制(或默认为None,表示任何可用的内容)并返回最多这么多字节的数据(如果可用)。
当流在另一端关闭,并且您已经读取了所有数据(即您已经返回了所有数据,并且未来不可能再有更多数据),则返回“None”。
def nonblock_read(stream, limit=None, forceMode=None)
‘’’
nonblock_read - 读取给定流(如文件对象或套接字)上可用的任何数据,而不阻塞且不考虑换行符。
@param stream - 流(如文件对象或套接字)
@param limit <None/int> - 要读取的最大字节数。如果为None或0,则读取所有可用的数据。
@param forceMode <None/模式字符串> - 默认 None。如果为 None,则将自动检测。如果您想显式强制一个模式,请提供 'b' 表示二进制(字节)或 't' 表示文本(字符串)。这决定了返回类型。
@return <str 或 bytes,取决于流的模式> - 流上可用的任何数据,如果流在另一端关闭且所有数据都已读取,则返回“None”。
‘’’
请注意,您只能读取已从另一端刷新的数据,否则它不在缓冲区中。
如果您需要对来自终端的 sys.stdin 执行非阻塞读取,您需要使用 “tty.setraw(sys.stdin)” 将其设置为原始模式。请参阅 examples/simpleGame.py 中的示例。
示例用法
from nonblock import nonblock_read
pipe = subprocess.Popen([‘someProgram’], stdout=subprocess.PIPE)
…
while True
data = nonblock_read(pipe.stdout)
if data is None
# 所有数据已处理,子进程关闭了流
pipe.wait()
break
elif data
# 已读取一些数据,处理它
processData(data)
else
# 缓冲区中没有数据,但子进程没有关闭流
idleTask()
# 所有数据已处理,关注空闲任务
idleTask()
一个使用非阻塞读取来驱动输入同时始终刷新地图并移动怪物的简单游戏示例可以在:https://github.com/kata198/python-nonblock/blob/master/example/simpleGame.py
背景读取 - bgread
有时您可能希望从一个或多个流中在后台收集数据,并在稍后检查/处理数据。
python-nonblock 通过一个名为 “bgread” 的方法提供了这个功能。您提供流对象和选项,它将输出一个对象,该对象将在后台线程中自动填充,当流上有可用数据时。
‘’’
bgread - 启动一个线程,该线程将以非阻塞方式从给定的流中读取,并将数据自动填充到返回的对象中。
@param stream <对象> - 要读取的流。套接字、文件等。
@param blockSizeLimit <None/整数> - 字节数。默认 65535。
如果为 None,则将从流中读取直到没有更多可用数据(未关闭,但已读取所有已刷新到流中的数据)。这对于较小的数据集是合适的,但这个数字实际上控制了在此流上花费的 CPU 时间与您的应用程序中的其他所有事情相比。默认的 65535 字节是相当多的数据。
@param pollTime <浮点数> - 默认 .03(30ms)。从流中读取所有可用数据后,等待这么多秒再检查是否有更多数据。
这里的数字较小意味着优先级较高,即更多的周期将用于检查和收集后台数据。由于这是一个非阻塞读取,此值是“阻塞”,它将执行上下文返回到应用程序的其余部分。默认的 100ms 在大多数情况下应该是合适的。如果是真正的空闲数据收集,您可能想尝试 1 秒的值。
@param closeStream <布尔值> - 默认 True。如果为 True,则在另一端关闭并读取所有数据后,将调用流对象的“close”方法。
注意事项 -
blockSizeLimit / pollTime 是您的有效最大吞吐量。实际吞吐量将低于此数字,因为实际吞吐量由以下定义
T = (blockSizeLimit / pollTime) - DeviceReadTime(blockSizeLimit)
使用默认值 .03 和 65535 意味着您将每秒读取多达 2 MB 的数据。请注意,在 I/O 上花费的时间越多,用于执行其他任务的时间就越少。
@return - 该函数的返回值是一个BackgroundReadData对象。该对象包含一个属性“blocks”,它是一个列表,包含从流中读取的非零长度块。对象还包含一个计算属性“data”,它是一个字符串/字节(取决于流模式),表示当前已读取的所有数据。当流关闭时,“isFinished”属性将被设置为True。在读取过程中发生的任何异常都将导致线程终止,并将“error”属性设置为异常。
‘’’
例如
inputData = bgread(sys.stdin)
processThings() # 执行一些耗时操作
typedData = inputData.data # 获取在‘processThings’期间发生的所有输入。
后台写入 - bgwrite
python-nonblock提供了一种简洁的方式来以非阻塞、可配置和交互式支持的方式写入流。
此功能的核心来自于bgwrite函数
def bgwrite(fileObj, data, closeWhenFinished=False, chainAfter=None, ioPrio=4)
‘’’
bgwrite - 启动后台写入过程
@param fileObj <stream> - 由fd支持的流
@param data <str/bytes/list> - 要写入的数据。如果提供列表,则后续每个元素将写入到fileObj并刷新。如果提供字符串/字节,则将根据选择的#BackgroundIOPriority进行分块。如果需要与选择的ioPrio不同的分块,请使用#bgwrite_chunk函数。
分块使数据在另一端更快地可用,减少此端的iowait,从而提高交互性(以吞吐量为代价)。
@param closeWhenFinished <bool> - 如果为True,则提供的fileObj将在所有数据写入后关闭。默认False。
@param chainAfter <None/BackgroundWriteProcess> - 如果提供BackgroundWriteProcess对象(bgwrite*函数的返回值),则此数据将在与提供的对象关联的数据写入完成后才进行写入。
使用此功能可以排队多个后台写入,同时在结果流中保持顺序。
@return - BackgroundWriteProcess - 表示此操作状态的对象。@see BackgroundWriteProcess
‘’’
您可以通过使用“chainAfter”参数并提供一个之前的“bgwrite”或“bgwrite_chunk”函数的返回值来创建要写入给定流的队列。这将等待之前的bgwrite完成后再开始下一个。
bgwrite将以块的形式写入数据,并基于预定义的BackgroundIOPriority或您提供的自定义BackgroundIOPriority(有关参数,请参阅下面的“完整文档”)进行启发式操作,以提供其他正在运行的线程和计算的用户交互性。
示例
可以在以下位置找到使用多个bgwrite以及执行CPU密集型计算的脚本的示例:https://github.com/kata198/python-nonblock/blob/master/testWrite.py
完整文档
更改
见:https://raw.githubusercontent.com/kata198/python-nonblock/master/ChangeLog