有些场景中,需要确保程序不被重复运行,也就是程序只在一个进程中被执行 (e.g., 微信)
程序单例运行的解决方案有:进程检测、端口抢占、文件锁
本文的代码采用了进程检测的手段,在主代码运行之前检测程序的运行状态 (check_running_status),如果当前程序已在一个进程中运行,则报错退出
check_running_status 的核心流程如下:
- 根据当前 py 文件所在路径生成程序标识,并生成临时文件的名称
- 读取临时文件中的进程信息,判断其所描述的进程是否存在;若存在则报错
- 在临时文件中写入当前进程的信息
# ./test.py
def check_running_status():
''' 通过临时文件, 保证当前程序只在一个进程中被执行'''
import os
import psutil
from pathlib import Path
# 根据所运行的 py 文件生成程序标识
exeid = (Path.cwd() / Path(__file__).name).resolve().as_posix().split(':')[-1].replace('/', '')
f = (Path(os.getenv('tmp')) / f'py-{exeid}').with_suffix('.txt')
# 读取文件, 并判断是否已有进程存在
cur = psutil.Process()
if f.is_file():
try:
_pid, time = f.read_text().split()
other = psutil.Process(int(_pid))
except:
other, time = cur, cur.create_time() + 1
# 退出: 文件所描述的进程仍然存在
if other.create_time() == float(time):
raise RuntimeError(f'The current program has been executed in process {other.pid}')
# 继续: 创建文件描述当前进程
f.write_text(' '.join(map(str, [cur.pid, cur.create_time()])))
if __name__ == '__main__':
check_running_status()
# ---------- 主程序 ----------
input('原神启动')
将上述代码写于 ./test.py 中,再将以下代码写于 ./tmp.py 中
# ./tmp.py
import os
os.system('python test.py')
同时运行这两个程序,则可发现其中一个程序报错
Traceback (most recent call last):
File "test.py", line 25, in <module>
check_running_status()
File "test.py", line 19, in check_running_status
raise RuntimeError(f'The current program has been executed in process {other.pid}')
RuntimeError: The current program has been executed in process 28684