将未缓冲的标准输出从子进程传输到 websocket
Pipe unbuffered stdout from subprocess to websocket
如何将标准输出从子进程传输到 websocket 而无需等待换行符?
目前,下面的代码仅在换行符上发送标准输出。
子进程为脚本附加的代码 运行。输出是否没有从那里正确刷新?
send_data.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);
};
我承认这个问题与这些问题类似:
catching-stdout-in-realtime-from-subprocess
how-do-i-get-real-time-information-back-from-a-subprocess-popen-in-python-2-5
intercepting-stdout-of-a-subprocess-while-it-is-running
然而 none 的解决方案在子进程中没有换行符的情况下工作。
如果你写
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:(示例读取 stddout 无缓冲)
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 读取数据。
您应该读取您的子进程产生的任何数据,就像之前任何管道缓冲区独立阻塞一样,无论这是 stdout 还是 stderr。
您可以使用 select.select()
( https://docs.python.org/3.8/library/select.html#select.select ) 来决定是否必须从 stdout 或 stderr
读取
如何将标准输出从子进程传输到 websocket 而无需等待换行符? 目前,下面的代码仅在换行符上发送标准输出。
子进程为脚本附加的代码 运行。输出是否没有从那里正确刷新?
send_data.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);
};
我承认这个问题与这些问题类似:
catching-stdout-in-realtime-from-subprocess
how-do-i-get-real-time-information-back-from-a-subprocess-popen-in-python-2-5
intercepting-stdout-of-a-subprocess-while-it-is-running
然而 none 的解决方案在子进程中没有换行符的情况下工作。
如果你写
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:(示例读取 stddout 无缓冲)
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 读取数据。
您应该读取您的子进程产生的任何数据,就像之前任何管道缓冲区独立阻塞一样,无论这是 stdout 还是 stderr。
您可以使用 select.select()
( https://docs.python.org/3.8/library/select.html#select.select ) 来决定是否必须从 stdout 或 stderr