后台运行 Python
如何运行
在后台运行 Python 程序的方式取决于操作系统以及具体需求(是否需要退出后继续运行、查看输出等)。以下是几种常用方法:
1. 使用 & (Linux/Unix/MacOS)
在命令末尾加上 &
,可以让程序在后台运行。
示例:
python your_script.py &
- 优点:简单快速。
- 缺点:如果关闭终端,程序也会终止。
2. 使用 nohup (Linux/Unix/MacOS)
nohup
允许程序在终端关闭后继续运行。
示例:
nohup python your_script.py > output.log 2>&1 &
- > \gt > output.log:将标准输出保存到 output.log 文件。
- 2>&1:将标准错误输出重定向到标准输出。
查看运行状态:
jobs
停止任务:
找到对应的进程号(PID),然后用 kill
命令结束任务:
ps -ef | grep your_script.py
kill PID
3. 使用 screen 或 tmux (Linux/Unix/MacOS)
这两个工具允许创建虚拟终端,程序可以在其中运行,即使断开连接也不会中断。
使用 screen:
- 启动一个新的 screen 会话:
screen -S my_session
- 在会话中运行程序:
python your_script.py
- 按下 Ctrl+A,然后按 D 来退出到后台。
- 重新进入会话:
screen -r my_session
使用 tmux:
类似于 screen
,更加现代化,命令类似。
4. 使用 Windows 的 start 命令
在 Windows 中,可以用 start
在后台运行 Python 程序。
示例:
start python your_script.py
5. 使用任务调度工具
(Linux/Unix/MacOS)
使用 cron
或 systemd
来安排脚本运行。
(Windows)
使用「任务计划程序」运行脚本。
6. 使用 Process Manager(如 Supervisor 或 PM2)
- Supervisor:适合管理长期运行的 Python 脚本。
- PM2:通常用于 Node.js,也支持 Python 程序。
示例 (PM2 安装后运行):
pm2 start your_script.py --interpreter=python3
7. 使用 Python 的多线程或守护进程
用 Python 自带的库运行守护程序,例如:
import threadingdef your_function():while True:print("Running in the background...")time.sleep(10)thread = threading.Thread(target=your_function, daemon=True)
thread.start()
总结
方法 | 平台 | 是否支持断开后继续运行 | 备注 |
---|---|---|---|
& | Linux/MacOS | 否 | 简单但不能断开终端 |
nohup | Linux/MacOS | 是 | 常用,适合简单脚本 |
screen | Linux/MacOS | 是 | 虚拟终端,多任务管理 |
tmux | Linux/MacOS | 是 | 更现代的虚拟终端 |
start | Windows | 否 | 适合 Windows 的简单运行 |
守护进程 | 所有平台 | 是 | 高级用法,需手动编写代码 |
根据需求选择合适的方案即可!
出现引入模块不存在怎么办?
在执行某个测试模块时出现提示,显示自定义模块data
不存在,但是在PyCharm下运行正常。错误信息如下:
Traceback (most recent call last):File "XXX.py", line 2, in <module>from data import *
ModuleNotFoundError: No module named 'data'
大部分情况下,此类问题是由于包的路径没有设置正确所致。通过打印 PyCharm 和命令行下的 sys.path
路径信息对比,可以发现以下差异:
在当前目录下__init__
添加
import sys
print("系统路径",sys.path)
解决方法
向执行代码中添加根目录路径,一般添加在头部
方法一:写死绝对路径
import sys
sys.path.append('xxx/xxx/xxx/')
方法二:使用os获取
os.path.dirname获取目录,此处就是获取目录的父目录。如果目录层级更多,就需要多加一层 os.path.dirname
import os,sys
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(project_root)
方法三:os获取+/…/
如果层级更多,则需要多加"…/" ,看起来比方法二更加简洁点
import os,sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../')
方法四,直接加到环境变量path中
输入以下命令
export PYTHONPATH=$PYTHONPATH:/xxx/
export 命令输入只临时生效,重新连接会失效,或者直接修改环境配置~/.bashrc等配置加上这句可以实现永久解决问题,如果这个不能实现,考虑自己手动去执行添加
方法五,subprocess.run 使用env变量
有些人是在subprocess去执行脚本,这个时候用上述的方法就不太能永久解决问题。我们可以使用subprocess的env参数去做,代码如下
def run_script(self, script_path, *args):# 运行 Python 脚本path_parts = script_path.split('/')export_commands = []for i in range(1, len(path_parts)):path_part = '/'.join(path_parts[:i])export_commands.append(f'{path_part}')env = os.environ.copy()env['PYTHONPATH'] = ':'.join(export_commands) + ':' + env.get('PYTHONPATH', '')# print(f"env{env}")script_dir = os.path.dirname(script_path)command = [f'{self.venv_path}/bin/python3', script_path] + list(args)return self.run_command(command,cwd=script_dir,env=env)
def run_command(self, command, shell=False,cwd=None,env=None) -> Tuple[int, str]:# 执行命令result = subprocess.run(command, shell=shell, capture_output=True, text=True,cwd=cwd,env=env)print(f"returncode:{result.returncode}")return result.returncode
通过script_path地址变量解析,添加所有的路径到环境变量中,然后给subprocess.run做继承,subprocess.run如果不继承的,每开一个会话,都是新的变量环境。
总结:
可能还有其他方法,但大体上找不到module的问题,大部分是路径变量问题,按照这个思路去解决就可以解决大部分类似问题。
如果输出文件中没有内容怎么办?
如果使用以下命令运行 Python 脚本时:
nohup python your_script.py > output.log 2>&1 &
而输出文件 output.log
中没有 print
语句的内容,可能是由于以下原因:
1. 输出被缓冲(最常见原因)
在 Python 中,标准输出(sys.stdout
)默认是行缓冲或全缓冲模式,尤其是当输出被重定向到文件时。这意味着 print
的内容可能会积累在缓冲区中,直到程序结束或缓冲区满时才会写入到文件。
解决方法:
在脚本中强制关闭缓冲,使用以下任意方法:
- 在 print 中加 flush=True:
修改所有print
调用,强制刷新输出缓冲区。
print("This is a test message", flush=True)
- 运行脚本时禁用缓冲:
在运行命令中添加-u
参数,这会使 Python 以无缓冲模式运行:
nohup python -u your_script.py > output.log 2>&1 &
- 手动刷新缓冲:
使用sys.stdout.flush()
在每次输出后刷新缓冲。
import sys
print("This is a test message")
sys.stdout.flush()
2. print 输出到了 stderr
有时,print
输出意外地被写入了 stderr
,而不是 stdout
,可能由于代码中修改了标准输出流。
解决方法:
确保你的命令正确重定向了 stderr
到 stdout
,如:
nohup python your_script.py > output.log 2>&1 &
其中 2>&1
将标准错误重定向到标准输出。
3. print 被捕获或重定向
如果脚本内部重定向了 sys.stdout
,例如将输出流写到了其他地方,则 print
不会写入到默认输出。
解决方法:
检查代码中是否有类似以下操作:
import sys
sys.stdout = open("another_log.txt", "w")
- 如果有,请注释掉或修改它。
4. 输出文件路径问题
确认 output.log
的路径是否正确,或者脚本是否有权限写入该路径。
检查方法:
- 确认文件是否创建:
ls -l output.log
- 检查写入权限:
touch output.log
5. 脚本没有运行成功
如果脚本未成功启动,可能导致没有输出。
检查方法:
- 确认脚本是否运行:
ps -ef | grep your_script.py
- 查看 nohup.out 文件:
如果没有指定 > output.log,默认输出到 nohup.out 文件,检查其中是否有相关信息。
总结
最可能的原因是 缓冲问题,可以通过以下方式解决:
nohup python -u your_script.py > output.log 2>&1 &
或者在脚本中修改 print
:
print("Hello, World!", flush=True)