Python应用程序由于子进程而变得无响应

Python应用程序由于子进程而变得无响应,python,linux,raspberry-pi,Python,Linux,Raspberry Pi,我用Flask编写了一个Python应用程序,它提供了一个简单的网站,我可以用它在我的Raspberry Pi(微型计算机)上开始播放流式视频。基本上,该应用程序允许be将我的手机或平板电脑用作遥控器 我在Mac OS上测试了这个应用程序,它运行得很好。在将其部署到Raspberry Pi(安装了Debian的Raspbian变体)之后,它可以很好地为网站服务,并且开始播放也可以按预期工作。但是,停止播放失败 相关代码位于此处: 子流程的启动方式如下: cmd = 'python2.7 mlbp

我用Flask编写了一个Python应用程序,它提供了一个简单的网站,我可以用它在我的Raspberry Pi(微型计算机)上开始播放流式视频。基本上,该应用程序允许be将我的手机或平板电脑用作遥控器

我在Mac OS上测试了这个应用程序,它运行得很好。在将其部署到Raspberry Pi(安装了Debian的Raspbian变体)之后,它可以很好地为网站服务,并且开始播放也可以按预期工作。但是,停止播放失败

相关代码位于此处:

子流程的启动方式如下:

cmd = 'python2.7 mlbplay.py v=%s j=%s/%s/%s i=t1' % (team, mm, dd, yy)
player = subprocess.Popen(cmd, shell=True, bufsize=-1, cwd=sys.argv[1])
rmtpdump <some_options_and_url> | mplayer -
这个很好用

子流程应在此之后停止:

player.send_signal(signal.SIGINT)
player.communicate()
这在Mac OS上确实有效,但在Raspberry Pi上不起作用:应用程序将挂起,直到子进程(以
cmd
启动)自行完成。子流程似乎未发送或未接收
SIGINT

有什么想法吗


(我也在这里发布了这个问题:因为我不知道这是操作系统问题还是Python/Flask相关问题。)

更新: 尝试使用下面Jan Vlcinsky建议的
player.communicate()
(最终看到警告后)没有帮助

我正在考虑使用Jan Vlcinsky提出的解决方案,但如果Flask甚至没有收到请求,我认为这不会收到问题

更新2: 昨天晚上,我很幸运地遇到了这样一种情况:我能够准确地指出问题所在。用相关代码更新了问题

我觉得Jan Vlcinsky的解决方案只会将问题转移到另一个应用程序,这将保持Flask应用程序的响应性,但会让新应用程序挂起

更新3: 我编辑了问题的原始部分,以删除我现在知道不相关的内容

更新4:在@shavenwarthog的评论之后,以下信息可能非常相关:

在Mac上,mlbplay.py启动如下内容:

cmd = 'python2.7 mlbplay.py v=%s j=%s/%s/%s i=t1' % (team, mm, dd, yy)
player = subprocess.Popen(cmd, shell=True, bufsize=-1, cwd=sys.argv[1])
rmtpdump <some_options_and_url> | mplayer -
我现在猜测,最后一行启动了一个新的进程组,它没有被
SIGINT
信号终止,从而使我的应用程序挂起。如果是这样,我应该以某种方式获取该组的进程组ID,以便能够正确终止它。有人能证实这一点吗

更新5:omxplayer确实处理
SIGINT

更新6:事实证明,我的SIGINT在命令链的某个地方以某种方式转换为SIGTERM。omxplayer没有正确处理SIGTERM,这似乎就是问题所在。我通过实现一个shell脚本来解决这个问题,该脚本管理信号并将它们转换为适当的omxplayer命令(类似于Jan建议的蹩脚版本)

解决方案:问题出在
播放器中。发送信号()
。该信号在命令链中处理不当,导致父应用程序挂起。解决方案是为不能很好地处理信号的命令实现包装器


另外:使用
Popen(cmd.split())
而不是使用
shell=True
。这在发送信号时效果更好

问题在以下代码段中标记:

@app.route('/watch/<year>/<month>/<day>/<home>/<away>/')
def watch(year, month, day, home, away):
    global session
    global watching
    global player

    # Select video stream
    fav = config.get('favorite')
    if fav:
        fav = fav[0] # TODO: handle multiple favorites
        if fav in (home, away):
            # Favorite team is playing
            team = fav
        else:
            # Use stream of home team
            team = home
    else:
        # Use stream of home team
        team = home

    # End session
    session = None

    # Start mlbplay
    mm = '%02i' % int(month)
    dd = '%02i' % int(day)
    yy = str(year)[-2:]
    cmd = 'python2.7 mlbplay.py v=%s j=%s/%s/%s' % (team, mm, dd, yy)
    # problem is here ----->
    player = subprocess.Popen(cmd, shell=True, cwd=sys.argv[1])
    # < ------problem is here

    # Render template
    game = {}
    game['away_code'] = away
    game['away_name'] = TEAMCODES[away][1]
    game['home_code'] = home
    game['home_name'] = TEAMCODES[home][1]
    watching = game
    return flask.render_template('watching.html', game=game)
@app.route('/watch)/////


优点是,您可以非常轻松地创建其他前端(如命令行前端,甚至远程前端)。

还有一个难题:
proc.terminate()
vs
send\u signal

下面的代码派生一个“播放器”(在本例中只是一个带有
sleep
的shell),然后打印其进程信息。它等待片刻,
terminate
s播放器,然后验证进程是否已停止,是否已停止

感谢@Jan Vlcinsky在代码中添加了
proc.communicate()

(我正在运行Linux Mint LMDE,这是Debian的另一个变体。)

来源 输出
你能分享一些代码吗?我会对你的Flask代码感兴趣(理想情况下是展示问题的完整工作示例,但至少是部分代码,它确实是
subprocess.Popen
)。完整的代码在这里托管:子流程在第142行启动,在第1630行停止。我同意将控制器从接口中分离是一个好主意(尽管对于这个小项目来说似乎有点过分)。尽管如此:a)为什么调用其他流程的子流程会出现问题?(顺便说一句,它确实启动了一系列其他流程)。b) 如果
std*
缓冲区被填满是真的(我猜这些缓冲区在Raspberry Pi上可能比在Mac上小),为什么它还会阻止Flask应用程序?这不是违背了子进程的全部目的吗?我更愿意向进程发送
SIGINT
,因为这个信号被显式地处理,作为一种优雅地退出我试图运行的程序的方式。发送
SIGTERM
对我来说似乎有点太严格了。@ludo我明白你的意思了。请注意,
SIGTERM
允许优雅退出;这是不可伪装的
SIGKILL。我期待着解决方案!不幸的是,mlbplay不是我的程序,所以我不能添加
SIGTERM
处理程序。此外,如果
SIGINT
没有到达,为什么
SIGTERM
SIGINT/SIGTERM
应该相同;他们都是可以伪装的。如果发送SIGTERM,会发生什么情况?它的行为是否与SIGINT不同?如果您使用的是以下mlbplay.py,那么它没有任何信号处理程序。Python进程可能正在接收信号,但子进程不会让它死掉。链接指向一个旧版本;这是最新的:在第384行,它捕捉到键盘中断以停止播放。“但是子进程不会让它死亡。”->这可能是一个好的观点。在Mac OS上,我使用的是另一种方式
* player started, PID 20393
Process Details:
F S UID        PID  PPID  C PRI  NI ADDR SZ WCHAN  STIME TTY        TIME CMD
0 S johnm    20393 20391  0  80   0 -  1110 wait   17:30 pts/4      0:00 /bin/sh -c /bin/sleep 123

*killing player
Process Details:
F S UID        PID  PPID  C PRI  NI ADDR SZ WCHAN  STIME TTY        TIME CMD