Android 为什么我运行adb shell monkey命令的python脚本会因大量事件而崩溃?

Android 为什么我运行adb shell monkey命令的python脚本会因大量事件而崩溃?,android,python,subprocess,adb,Android,Python,Subprocess,Adb,我编写了一个小python函数,它使用subprocess.popen运行adb shell monkey-p-v命令和adb logcat命令。对于大于100的值,这个程序崩溃,我不知道为什么 这是monkey_runner.py import os, subprocess def run_monkey_process(package, num_commands): monkeycmd = "adb shell monkey -p " + package + " -v " +

我编写了一个小python函数,它使用subprocess.popen运行adb shell monkey-p-v命令和adb logcat命令。对于大于100的值,这个程序崩溃,我不知道为什么

这是monkey_runner.py

import os, subprocess
def run_monkey_process(package, num_commands):
        monkeycmd = "adb shell monkey -p " + package + " -v " + num_commands
        monkeyprocess = subprocess.Popen(monkeycmd, stdout=subprocess.PIPE)
        logcatcmd = "adb logcat"
        logcatprocess = subprocess.Popen(logcatcmd, stdout=subprocess.PIPE)
        monkeystring = monkeyprocess.communicate(input=None)[0]
        logcatstring = logcatprocess.communicate(input=None)[0]
        monkeyreturncode = monkeyprocess.poll()
        logcatreturncode = logcatprocess.poll()


        if(monkeyreturncode >=0):
                monkeyprocess.kill()
                logcatprocess.kill()

                return monkeystring, logcatstring

        else:
                print 'command failure'
                return 'you', 'fail'
我也可以把我的gui代码放在这里,但没什么特别的

这是stacktrace

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python27\lib\lib-tk\Tkinter.py", line 1470, in __call__
    return self.func(*args)
  File "C:\Users\brandon.dalesandro\Desktop\Zonar\mankey\monkey_runner_gui.py", line 25, in goCallBack
    returned = run_monkey_process(package, num)
  File "C:\Users\brandon.dalesandro\Desktop\Zonar\mankey\monkey_runner.py", line 8, in run_monkey_process
    logcatstring = logcatprocess.communicate(input=None)[0]
  File "C:\Python27\lib\subprocess.py", line 798, in communicate
    stdout = _eintr_retry_call(self.stdout.read)
  File "C:\Python27\lib\subprocess.py", line 478, in _eintr_retry_call
    return func(*args)
KeyboardInterrupt
这可能是你的问题,但如果没有更多的信息,很难判断

您已经为子流程指定了一个管道,但直到子流程完成后才读取它。文档中的说明解释了为什么这是不好的:

这将在使用
stdout=PIPE
和/或
stderr=PIPE
时死锁,并且子进程生成足够多的输出到管道,从而阻止等待OS管道缓冲区接受更多数据。使用
communicate()
来避免这种情况

当没有足够的数据填充管道缓冲区时,它将适用于少量命令,但挂起用于较大数量的命令,这是非常合理的

循环使用
poll
而不是调用
wait
没有任何帮助;它所做的只是毫无理由地消耗100%的CPU。你还是没在看烟斗里的东西

而在流程完成后调用
通信
,也无济于事。如果管道已满,子进程将永远被阻塞,
poll
将永远不会返回值,您甚至无法进行
通信

由于
通信
已经有了自己的
等待
,因此您真正需要的就是:

monkeyprocess = subprocess.Popen(monkeycmd, stdout=subprocess.PIPE, bufsize=1)
monkeystring = monkeyprocess.communicate(input=None)[0]
returncode = monkeyprocess.returncode

“崩溃”是什么意思?它是否真的隔离故障和转储核心?或者打印出异常回溯?或者返回失败?这不是您的问题,但是…您永远不应该循环使用
monkeyprocess.poll()
;这将与只调用
monkeyprocess.wait()
具有相同的效果,只是为了无故消耗100%的CPU。(当我们这样做的时候,千万不要做
==None
,do
就是None
,如果
处于
状态时,在
周围放置额外的参数会使代码更难阅读。)此外,在
终止后调用
kill
也没有好的理由。在POSIX上,如果
SIGTERM
没有终止进程,
SIGKILL
可能没有帮助。在Windows上,它们都做完全相同的事情。在kill之后调用
communicate
是没有用的,因为同样的原因,在循环
poll
或调用
wait
之后也是没有用的。当我说崩溃时,我的意思是它会一直挂起,直到我用任务管理器杀死它。好的,“挂起”或“冻结”与“崩溃”是完全不同的,如果你使用正确的术语而不是让人们猜测,你会得到更好的答案。不管怎么说,如果你只是在等待,很可能是在
poll
的循环中,所以我的答案会解决它。(但最好知道它挂起的位置,只需在bash/cmd shell中运行它,使用control-C停止它,并查看从打印出来的
键盘中断
的回溯即可看到。)感谢您的回答。我如何收集adb信息,而不填充管道?我可以定期将其添加到字符串或文件中并清除管道吗?为了避免阻塞管道,您需要循环
proc.stdout.read(n)
,并确保不执行任何阻塞操作(如旋转
proc.poll()
)以阻止您以数据进入的速度读取数据)。但是,如果您只需通过调用
communicate
以简单的方式进行操作,它已经为您解决了这一问题。这就是为什么文档建议尽可能使用
沟通
,而不是自己尝试。