草庐IT

python - 在 python 中从 stdin 无缓冲读取

coder 2023-08-22 原文

我正在编写一个 python 脚本,它可以像这样通过管道从另一个命令读取输入

batch_job | myparser

我的脚本 myparser 处理 batch_job 的输出并写入它自己的标准输出。我的问题是我想立即看到输出(batch_job 的输出是逐行处理的)但是似乎有这个臭名昭著的标准输入缓冲(据称是 4KB,我还没有验证)延迟了一切。

问题已经讨论过了here herehere .

我尝试了以下方法:

  • 使用 os.fdopen(sys.stdin.fileno(), 'r', 0) 打开标准输入
  • 在我的 hashbang 中使用 -u:#!/usr/bin/python -u
  • 在调用脚本之前设置 export PYTHONUNBUFFERED=1
  • 在读取每一行后刷新我的输出(以防万一问题来自输出缓冲而不是输入缓冲)

我的 python 版本是 2.4.3 - 我无法升级或安装任何其他程序或软件包。我怎样才能摆脱这些延迟?

最佳答案

我在遗留代码中遇到过同样的问题。这似乎是 Python 2 的 file 对象的 __next__ 方法的实现问题;它使用 Python 级缓冲区(-u/PYTHONUNBUFFERED=1 不影响,因为那些只取消缓冲 stdio FILE * 本身,但是 file.__next__ 的缓冲不相关;同样,stdbuf/unbuffer 不能改变任何缓冲,因为 Python 替换了 C 运行时创建的默认缓冲区;file.__init__ 对新打开的文件所做的最后一件事是调用 PyFile_SetBufSize,它使用 setvbuf/setbuf [API] 来替换默认的 stdio 缓冲区)。

当您有以下形式的循环时会出现问题:

for line in sys.stdin:

__next__ 的第一次调用(由 for 循环隐式调用以获取每个 line)最终阻塞以填充之前的 block 生产单线。

存在三种可能的修复方法:

  1. (仅适用于 Python 2.6+)使用 io 模块(作为内置从 Python 3 向后移植)重新包装 sys.stdio 以绕过 file 完全支持(坦率地说是优越的)Python 3 设计(它一次使用一个系统调用来填充缓冲区,而不会阻塞整个请求的读取;如果它要求 4096 字节并得到3, 它将查看是否有一行可用并生成它)所以:

    import io
    import sys
    
    # Add buffering=0 argument if you won't always consume stdin completely, so you 
    # can't lose data in the wrapper's buffer. It'll be slower with buffering=0 though.
    with io.open(sys.stdin.fileno(), 'rb', closefd=False) as stdin:
        for line in stdin:
            # Do stuff with the line
    

    这通常比选项 2 更快,但更冗长,并且需要 Python 2.6+。它还允许重新包装是 Unicode 友好的,通过将模式更改为 'r' 并可选择传递输入的已知 encoding(如果它不是区域设置默认值)无缝获取 unicode 行而不是(仅限 ASCII)str

  2. (任何版本的 Python)通过使用 file.readline 解决 file.__next__ 的问题;尽管预期的行为几乎相同,readline 并没有做自己的(过度)缓冲,它委托(delegate)给 C stdiofgets(默认构建settings) 或手动循环调用 getc/getc_unlocked 进入缓冲区,该缓冲区在到达行尾时准确停止。通过将它与双参数 iter 结合使用,您可以获得几乎相同的代码而不会过于冗长(它可能比之前的解决方案慢,具体取决于是否使用 fgets引擎盖,以及 C 运行时如何实现它):

    # '' is the sentinel that ends the loop; readline returns '' at EOF
    for line in iter(sys.stdin.readline, ''):
        # Do stuff with line
    
  3. 移至 Python 3,它没有这个问题。 :-)

关于python - 在 python 中从 stdin 无缓冲读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33305131/

有关python - 在 python 中从 stdin 无缓冲读取的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  3. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  4. Python 相当于 Perl/Ruby ||= - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

  5. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  6. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  7. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  8. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

  9. 「Python|Selenium|场景案例」如何定位iframe中的元素? - 2

    本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决

  10. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

随机推荐