首页 > 解决方案 > Python3 / subprocess.check_output / Timeout 不适用于每个命令

问题描述

我正在使用 Python 3.7.3 运行 Debian 10.8,并在脚本中运行一个子进程,我想在几秒钟后中断该子进程。这适用于 cmd_1 但不适用于以下示例中的 cmd_2 (永远不会触发超时):

import subprocess
import os, sys

# collect proxies and verify
try:
    # cmd_1 = "while true; do sleep 1; done"
    cmd_2 = "proxybroker find --types HTTPS -l 1000 --outfile proxybroker.txt"
    timeout_sec = 3
    subprocess.check_output(cmd_2, shell=True, timeout=timeout_sec)
except Exception as e:
    print(e)

如果我在 bash 中运行 cmd_2,它工作正常。我确实使用pip3 install proxybroker.

在另一个运行 Ubuntu 21.04 的系统上,超时适用于这两个命令。感谢有人可以提供提示。

标签: pythonpython-3.xsubprocess

解决方案


我无法准确解释为什么会发生这种情况,但摆脱无偿的外壳可以解决它。

tripleee@debian-buster-docker$ cat >subn.py
import subprocess
# import os, sys  # unused import

# collect proxies and verify
try:
  subprocess.check_output(['proxybroker', 'find', '--types', 'HTTPS', '-l', '1000', '--outfile', 'proxies.txt'], timeout=3)
except Exception as e:
  print(e)
^D
tripleee@debian-buster-docker$ python3 subn.py 
Command '['proxybroker', 'find', '--types', 'HTTPS', '-l', '1000', '--outfile', 'proxies.txt']' timed out after 3 seconds

我注意到当我用 KeyboardInterrupt 中断它时,您最初的尝试确实将超时消息打印为回溯的一部分。

tripleee@debian-buster-docker$ python3 sub.py
^CTraceback (most recent call last):
  File "/usr/lib/python3.7/subprocess.py", line 474, in run
    stdout, stderr = process.communicate(input, timeout=timeout)
  File "/usr/lib/python3.7/subprocess.py", line 939, in communicate
    stdout, stderr = self._communicate(input, endtime, timeout)
  File "/usr/lib/python3.7/subprocess.py", line 1682, in _communicate
    self._check_timeout(endtime, orig_timeout)
  File "/usr/lib/python3.7/subprocess.py", line 982, in _check_timeout
    raise TimeoutExpired(self.args, orig_timeout)
subprocess.TimeoutExpired: Command 'proxybroker find --types HTTPS -l 1000 --outfile proxybroker.txt' timed out after 3 seconds

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "sub.py", line 9, in <module>
    subprocess.check_output(cmd_2, shell=True, timeout=timeout_sec)
  File "/usr/lib/python3.7/subprocess.py", line 395, in check_output
    **kwargs).stdout
  File "/usr/lib/python3.7/subprocess.py", line 477, in run
    stdout, stderr = process.communicate()
  File "/usr/lib/python3.7/subprocess.py", line 939, in communicate
    stdout, stderr = self._communicate(input, endtime, timeout)
  File "/usr/lib/python3.7/subprocess.py", line 1681, in _communicate
    ready = selector.select(timeout)
  File "/usr/lib/python3.7/selectors.py", line 415, in select
    fd_event_list = self._selector.poll(timeout)
KeyboardInterrupt

推荐阅读