python - 将无缓冲的标准输出从子进程管道传输到 websocket
问题描述
您如何将标准输出从子进程传输到 websocket 而无需等待换行符?目前,下面的代码仅在换行符上发送标准输出。
为子进程运行的脚本附加的代码。输出是否没有从那里正确刷新?
发送数据.py:
import asyncio
import websockets
import subprocess
import sys
import os
async def foo(websocket, path):
print ("socket open")
await websocket.send("successfully connected")
with subprocess.Popen(['sudo','python3', '-u','inline_print.py'],stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0, universal_newlines=True) as p:
for line in p.stdout:
line = str(line.rstrip())
await websocket.send(line)
p.stdout.flush()
for line in p.stderr:
line = str(line.rstrip())
await websocket.send(line)
p.stdout.flush()
start_server = websockets.serve(foo, "localhost", 8765)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
inline_print.py:
from time import sleep
import sys
loading = 'LOADING...LOADING...LOADING...LOADING...LOADING...'
for i in range(50):
print(loading[i], sep='', end=' ', flush=True)
sleep(0.1)
如果end=' '
更改为,end='\n'
则标准输出从send_data.py
实时发生。
js客户端:
var ws = new WebSocket('ws://localhost:8765/');
ws.onmessage = function(event) {
console.log(event.data);
};
我承认这个问题类似于这些:
如何-我-获取-实时-信息-从-a-subprocess-popen-in-python-2-5 返回
但是,如果没有子流程中的换行符,任何解决方案都无法工作。
解决方案
如果你写
for line in p.stdout:
然后你(有点)含蓄地说,你想等待一个完整的线路
你必须使用read(num_bytes)
而不是readline()
下面以一个例子来说明:
sub.py:(示例子进程)
import sys, time
for v in range(20):
print(".", end="")
sys.stdout.flush()
if v % 4 == 0:
print()
if v % 3 != 0:
time.sleep(0.5)
rdunbuf.py:(读取标准输出无缓冲的示例)
contextlib, time, subprocess
def unbuffered(proc, stream='stdout'):
stream = getattr(proc, stream)
with contextlib.closing(stream):
while True:
last = stream.read(80) # read up to 80 chars
# stop when end of stream reached
if not last:
if proc.poll() is not None:
break
else:
yield last
# open subprocess without buffering and without universal_newlines=True
proc = subprocess.Popen(["./sub.py"], stdout=subprocess.PIPE, bufsize=0)
for l in unbuffered(proc):
print(l)
print("end")
另请注意,如果您的代码在产生正常输出之前产生大量错误消息,则可能会阻塞,因为您首先尝试读取所有正常输出,然后才从 stderr 读取数据。
无论是标准输出还是标准错误,您都应该像在任何管道缓冲区独立阻塞之前一样读取子进程产生的任何数据。您可以使用select.select()
(https://docs.python.org/3.8/library/select.html#select.select)来决定是否必须从标准输出或标准错误中读取
推荐阅读
- html - 无法“整理”html 文件
- angular - ng test angular 5 不是已知元素
- python - Selenium(使用 python):如何将任何文本输入到 wiki textarea
- python - 使用 python pandas 我想在非空值上规范化数据框列
- java - 添加定义单词的功能
- javascript - 点击 TouchableHighlight 上的焦点文本输入
- scheduling - 无限循环任务的优先级抢占式调度
- ios - 展开 UITableViewCell UIImage
- c# - Office365 - 列出 O365 用户而不注册应用程序和生成令牌
- html - AngularJs - 将参数从网格结果行传递到外部网页