- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我需要一种方法来读取 Popen 创建的流中所有当前可用的字符,或者找出缓冲区中剩余的字符数。
背景:我想用 Python 远程控制一个交互式应用程序。到目前为止,我使用 Popen 创建了一个新的子进程:
process=subprocess.Popen(["python"],shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE, cwd=workingDir)
(我不是真的开始python,但实际的交互界面是相似的。)目前我读取了 1 个字节,直到我检测到进程已到达命令提示符:
output = ""
while output[-6:]!="SCIP> ":
output += process.stdout.read(1)
sys.stdout.write(output[-1])
return output
然后我通过 process.stdin.write("command\n")
开始一个冗长的计算。我的问题是,我无法检查计算是否完成,因为我无法检查流中的最后一个字符是否是提示符。 read()
或 read(n)
阻塞我的线程,直到它到达 EOF,它永远不会,因为交互式程序在被告知之前不会结束。以上述循环的方式寻找提示也行不通,因为提示只会在计算之后出现。
理想的解决方案是让我从流中读取所有可用字符,如果没有可读取的内容,则立即返回一个空字符串。
最佳答案
Popen 的标准输出的增量解析真的不是问题。只需将管道插入线程并让它通过输出擦洗,寻找分隔符。根据您的喜好,它可以将其通过管道传输到另一个管道/文件中,或者以异步模式将解析的“ block ”放在“堆栈”上。下面是一个基于自定义分隔符的 stdout 异步“分 block ”示例:
import cStringIO
import uuid
import threading
import os
class InputStreamChunker(threading.Thread):
'''
Threaded object / code that mediates reading output from a stream,
detects "separation markers" in the stream and spits out chunks
of original stream, split when ends of chunk are encountered.
Results are made available as a list of filled file-like objects
(your choice). Results are accessible either "asynchronously"
(you can poll at will for results in a non-blocking way) or
"synchronously" by exposing a "subscribe and wait" system based
on threading.Event flags.
Usage:
- instantiate this object
- give our input pipe as "stdout" to other subprocess and start it:
Popen(..., stdout = th.input, ...)
- (optional) subscribe to data_available event
- pull resulting file-like objects off .data
(if you are "messing" with .data from outside of the thread,
be curteous and wrap the thread-unsafe manipulations between:
obj.data_unoccupied.clear()
... mess with .data
obj.data_unoccupied.set()
The thread will not touch obj.data for the duration and will
block reading.)
License: Public domain
Absolutely no warranty provided
'''
def __init__(self, delimiter = None, outputObjConstructor = None):
'''
delimiter - the string that will be considered a delimiter for the stream
outputObjConstructor - instanses of these will be attached to self.data array
(intantiator_pointer, args, kw)
'''
super(InputStreamChunker,self).__init__()
self._data_available = threading.Event()
self._data_available.clear() # parent will .wait() on this for results.
self._data = []
self._data_unoccupied = threading.Event()
self._data_unoccupied.set() # parent will set this to true when self.results is being changed from outside
self._r, self._w = os.pipe() # takes all inputs. self.input = public pipe in.
self._stop = False
if not delimiter: delimiter = str(uuid.uuid1())
self._stream_delimiter = [l for l in delimiter]
self._stream_roll_back_len = ( len(delimiter)-1 ) * -1
if not outputObjConstructor:
self._obj = (cStringIO.StringIO, (), {})
else:
self._obj = outputObjConstructor
@property
def data_available(self):
'''returns a threading.Event instance pointer that is
True (and non-blocking to .wait() ) when we attached a
new IO obj to the .data array.
Code consuming the array may decide to set it back to False
if it's done with all chunks and wants to be blocked on .wait()'''
return self._data_available
@property
def data_unoccupied(self):
'''returns a threading.Event instance pointer that is normally
True (and non-blocking to .wait() ) Set it to False with .clear()
before you start non-thread-safe manipulations (changing) .data
array. Set it back to True with .set() when you are done'''
return self._data_unoccupied
@property
def data(self):
'''returns a list of input chunkes (file-like objects) captured
so far. This is a "stack" of sorts. Code consuming the chunks
would be responsible for disposing of the file-like objects.
By default, the file-like objects are instances of cStringIO'''
return self._data
@property
def input(self):
'''This is a file descriptor (not a file-like).
It's the input end of our pipe which you give to other process
to be used as stdout pipe for that process'''
return self._w
def flush(self):
'''Normally a read on a pipe is blocking.
To get things moving (make the subprocess yield the buffer,
we inject our chunk delimiter into self.input
This is useful when primary subprocess does not write anything
to our in pipe, but we need to make internal pipe reader let go
of the pipe and move on with things.
'''
os.write(self._w, ''.join(self._stream_delimiter))
def stop(self):
self._stop = True
self.flush() # reader has its teeth on the pipe. This makes it let go for for a sec.
os.close(self._w)
self._data_available.set()
def __del__(self):
try:
self.stop()
except:
pass
try:
del self._w
del self._r
del self._data
except:
pass
def run(self):
''' Plan:
- We read into a fresh instance of IO obj until marker encountered.
- When marker is detected, we attach that IO obj to "results" array
and signal the calling code (through threading.Event flag) that
results are available
- repeat until .stop() was called on the thread.
'''
marker = ['' for l in self._stream_delimiter] # '' is there on purpose
tf = self._obj[0](*self._obj[1], **self._obj[2])
while not self._stop:
l = os.read(self._r, 1)
print('Thread talking: Ordinal of char is:%s' %ord(l))
trash_str = marker.pop(0)
marker.append(l)
if marker != self._stream_delimiter:
tf.write(l)
else:
# chopping off the marker first
tf.seek(self._stream_roll_back_len, 2)
tf.truncate()
tf.seek(0)
self._data_unoccupied.wait(5) # seriously, how much time is needed to get your items off the stack?
self._data.append(tf)
self._data_available.set()
tf = self._obj[0](*self._obj[1], **self._obj[2])
os.close(self._r)
tf.close()
del tf
def waitforresults(ch, answers, expect):
while len(answers) < expect:
ch.data_available.wait(0.5); ch.data_unoccupied.clear()
while ch.data:
answers.append(ch.data.pop(0))
ch.data_available.clear(); ch.data_unoccupied.set()
print('Main talking: %s answers received, expecting %s\n' % ( len(answers), expect) )
def test():
'''
- set up chunker
- set up Popen with chunker's output stream
- push some data into proc.stdin
- get results
- cleanup
'''
import subprocess
ch = InputStreamChunker('\n')
ch.daemon = True
ch.start()
print('starting the subprocess\n')
p = subprocess.Popen(
['cat'],
stdin = subprocess.PIPE,
stdout = ch.input,
stderr = subprocess.PIPE)
answers = []
i = p.stdin
i.write('line1 qwer\n') # will be in results
i.write('line2 qwer\n') # will be in results
i.write('line3 zxcv asdf') # will be in results only after a ch.flush(),
# prepended to other line or when the pipe is closed
waitforresults(ch, answers, expect = 2)
i.write('line4 tyui\n') # will be in results
i.write('line5 hjkl\n') # will be in results
i.write('line6 mnbv') # will be in results only after a ch.flush(),
# prepended to other line or when the pipe is closed
waitforresults(ch, answers, expect = 4)
## now we will flush the rest of input (that last line did not have a delimiter)
i.close()
ch.flush()
waitforresults(ch, answers, expect = 5)
should_be = ['line1 qwer', 'line2 qwer',
'line3 zxcv asdfline4 tyui', 'line5 hjkl', 'line6 mnbv']
assert should_be == [i.read() for i in answers]
# don't forget to stop the chunker. It it closes the pipes
p.terminate()
ch.stop()
del p, ch
if __name__ == '__main__':
test()
编辑:删除了关于“写入 proc 的标准输入是一次性的”的错误措辞
关于python - 如何从 subprocess.Popen.stdout 读取所有可用数据(非阻塞)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3076542/
我正在使用java引擎来处理一些内容。 我想知道这样会占用不必要的资源吗? command = 'some command to run my jar file' p = subprocess.Pop
我正在尝试使用以下代码块将一个进程的输出作为输入发送到另一个进程: p1 = Popen(command, stdout=PIPE) p2 = Popen(dgxmcmd, stdin=p1.stdo
popen 缓冲输出而系统没有。这是唯一的区别吗? 我知道 popen 和 system 都通过 shell 运行命令。但是,popen() 是否为 evil作为系统()? 最佳答案 看,从本质上讲,
用代码最容易解释: require 'timeout' puts "this block will properly kill the sleep after a second" IO.popen("
似乎既执行子进程又创建管道进行输入/输出,只是 subprocess 较新。 我的问题是,有没有subprocess.Popen可以做而os.popen不能做的功能,所以我们需要新模块subproce
我有一个生成以下输出的程序: ┌───────────────────────┐ │10 day weather forecast│
我正在使用以下命令来运行 shell 命令(创建子进程): cmd = "ls" process = subprocess.Popen(cmd, shell=True, stdout=subproce
得到结果后,我需要停止通过Python中的Popen发出的服务(在另一个线程的后台运行),但是以下方法失败了(只是使用ping)解释): class sample(threading.Thread):
Python - os.popen 和 subprocess.Popen 有什么区别? 最佳答案 os 进程功能被认为已过时。 subprocess 模块是在 Python 2.4 中引入的,作为与子
根据 python 文档 http://docs.python.org/library/subprocess.html ,建议将 os.popen 替换为 Popen 类,现在我有以下命令: impo
非常具体的问题(我希望):以下三个代码有什么区别? (我希望它只是第一个不等待子进程完成,而第二个和第三个会这样做。但我需要确定这是 only 的区别...) 我也欢迎其他评论/建议(尽管我已经很清楚
我有以下代码: pwd = '/home/user/svnexport/Repo/' updateSVN = "svn up " + pwd cmd = os.popen(updateSVN) get
我正在尝试编写简单的 c 函数,这将使我有可能看到从一个流到另一个流的数据传输进度,并将其显示在我的字符 LCD 上。 我设法传输数据并指示进度,但如何获得管道的结果? 所以基本上我想在 c 中做对应
我正在尝试使用 subprocess 模块与使用 Python 的命令行聊天机器人进行通信。 (http://howie.sourceforge.net/使用编译后的 win32 二进制文件,我有我的
我需要为 Ghostscript 创建一个 Monkey 补丁,我必须从 os.popen 迁移到 subsession.popen 因为我不能在我的系统中使用 shell . 我这样试过: def
在 Linux 操作系统上,下面的 python 代码提供了当前目录中的目录。 dirs = os.popen('ls -d */').read().split(os.linesep) print d
当我们从 Python 2.7.3 升级到 Python 2.7.5 时,大量使用 subprocess.Popen() 的内部库的自动化测试开始失败。该库用于线程环境。调试问题后,我能够创建一个简短
我无法得到它与 bash 相关或 python 子进程,但结果不同: >>> subprocess.Popen("echo $HOME", shell=True, stdout=subprocess.
这里我想执行一个命令,我必须在执行第一个命令后给这个命令输入。 我想执行 obex_test蓝牙模式命令而不是在我必须为启动服务器提供像's'这样的输入之后我怎么能给这个东西。这是我的代码,我写了这个
在我的 Lua 程序中,我必须捕获来自外部程序的输出。这个外部程序需要某些环境变量。所以我这样做: e = "" e = e .. "A=100;" e = e .. "B=Hi;" e = e ..
我是一名优秀的程序员,十分优秀!