前言
在使用 ArcGIS Pro 进行地理信息处理时,经常会遇到进程卡死、内存泄漏或服务异常等问题。特别是 ArcGISIndexingServer
进程,经常会在后台持续运行,消耗大量系统资源。本文将介绍如何通过 Python 自动化脚本来监控和管理 ArcGIS Pro 相关进程,提高工作效率。
1. 问题背景
1.1 常见问题
- 进程卡死:ArcGIS Pro 相关进程无响应
- 内存泄漏:长时间运行导致内存占用过高
- 服务异常:索引服务进程异常运行
- 资源占用:多个进程实例同时运行
1.2 传统解决方案的局限性
- 手动任务管理器操作繁琐
- 无法实时监控进程状态
- 缺乏自动化处理能力
- 没有详细的日志记录
2. 技术方案设计
2.1 核心技术栈
- Python 3.6+:主要开发语言
- psutil 库:进程管理核心库
- logging 模块:日志记录
- signal 模块:信号处理
2.2 系统架构
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 监控模块 │ │ 检测模块 │ │ 终止模块 │
│ (Monitor) │───▶│ (Detector) │───▶│ (Killer) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 日志模块 │ │ 配置模块 │ │ 异常处理 │
│ (Logger) │ │ (Config) │ │ (Exception) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
3. 核心代码实现
3.1 进程监控类设计
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
ArcGIS Pro 进程监控和自动终止脚本
功能: 持续监控系统进程,自动检测并终止 ArcGIS 相关进程
"""
import psutil
import time
import logging
import sys
from datetime import datetime
import signal
import os
class ArcGISProcessManager:
def __init__(self, check_interval=5, log_file="arcgis_manager.log"):
"""
初始化 ArcGIS 进程管理器
Args:
check_interval (int): 检查间隔时间(秒)
log_file (str): 日志文件名
"""
self.check_interval = check_interval
self.target_processes = [
"ArcGISIndexingServer",
"ArcGISPro",
"ArcGISPro.exe",
"ArcMap",
"ArcMap.exe"
]
self.running = True
# 设置日志
self.setup_logging(log_file)
# 注册信号处理器
signal.signal(signal.SIGINT, self.signal_handler)
signal.signal(signal.SIGTERM, self.signal_handler)
self.logger.info(f"🚀 ArcGIS 进程管理器已启动")
self.logger.info(f"🎯 监控进程: {', '.join(self.target_processes)}")
self.logger.info(f"⏰ 检查间隔: {self.check_interval}秒")
3.2 进程检测算法
python
def find_arcgis_processes(self):
"""
查找所有 ArcGIS 相关进程
Returns:
list: 进程对象列表
"""
arcgis_processes = []
try:
for proc in psutil.process_iter(['pid', 'name', 'cmdline', 'memory_info']):
try:
proc_name = proc.info['name'] or ""
proc_cmdline = ' '.join(proc.info['cmdline'] or [])
# 检查进程名匹配
for target in self.target_processes:
if target.lower() in proc_name.lower():
arcgis_processes.append({
'process': proc,
'name': proc_name,
'pid': proc.info['pid'],
'memory': proc.info['memory_info'].rss if proc.info['memory_info'] else 0
})
break
# 检查命令行匹配
if not any(target.lower() in proc_name.lower() for target in self.target_processes):
for target in self.target_processes:
if target.lower() in proc_cmdline.lower():
arcgis_processes.append({
'process': proc,
'name': proc_name,
'pid': proc.info['pid'],
'memory': proc.info['memory_info'].rss if proc.info['memory_info'] else 0
})
break
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
continue
except Exception as e:
self.logger.error(f"❌ 查找进程时出错: {e}")
return arcgis_processes
3.3 智能进程终止策略
python
def kill_process(self, proc_info):
"""
智能终止指定进程
Args:
proc_info (dict): 进程信息字典
Returns:
bool: 是否成功终止
"""
proc = proc_info['process']
pid = proc_info['pid']
name = proc_info['name']
memory = proc_info['memory']
try:
# 记录进程信息
memory_mb = memory / 1024 / 1024
self.logger.info(f"🔍 处理进程: PID={pid}, Name={name}, Memory={memory_mb:.1f}MB")
# 检查进程是否仍在运行
if not proc.is_running():
self.logger.info(f"ℹ️ 进程已不存在: PID={pid}")
return True
# 策略1: 优雅终止
self.logger.info(f"🔄 尝试优雅终止进程: PID={pid}")
proc.terminate()
# 等待进程结束
try:
proc.wait(timeout=10)
self.logger.info(f"✅ 进程已优雅终止: PID={pid}")
return True
except psutil.TimeoutExpired:
self.logger.warning(f"⚠️ 优雅终止超时,尝试强制终止: PID={pid}")
# 策略2: 强制终止
proc.kill()
try:
proc.wait(timeout=5)
self.logger.info(f"💀 进程已被强制终止: PID={pid}")
return True
except psutil.TimeoutExpired:
self.logger.error(f"❌ 无法终止进程: PID={pid}")
return False
except psutil.NoSuchProcess:
self.logger.info(f"ℹ️ 进程已不存在: PID={pid}")
return True
except psutil.AccessDenied:
self.logger.error(f"❌ 没有权限终止进程: PID={pid}")
return False
except Exception as e:
self.logger.error(f"❌ 终止进程时出错: PID={pid}, 错误: {e}")
return False
3.4 内存监控和预警
python
def check_memory_usage(self, proc_info):
"""
检查进程内存使用情况
Args:
proc_info (dict): 进程信息字典
Returns:
bool: 是否需要终止(内存使用过高)
"""
memory = proc_info['memory']
memory_mb = memory / 1024 / 1024
# 设置内存阈值(例如 2GB)
memory_threshold = 2 * 1024 * 1024 * 1024 # 2GB
if memory > memory_threshold:
self.logger.warning(f"⚠️ 进程内存使用过高: {memory_mb:.1f}MB > 2048MB")
return True
return False
def get_system_memory_info(self):
"""获取系统内存信息"""
try:
memory = psutil.virtual_memory()
return {
'total': memory.total,
'available': memory.available,
'percent': memory.percent,
'used': memory.used
}
except Exception as e:
self.logger.error(f"❌ 获取系统内存信息失败: {e}")
return None
4. 高级功能实现
4.1 进程白名单机制
python
def __init__(self, check_interval=5, log_file="arcgis_manager.log", whitelist=None):
# ... 其他初始化代码 ...
# 进程白名单(这些进程不会被终止)
self.whitelist = whitelist or [
"ArcGISPro.exe", # 主程序
"ArcGISProBackgroundGP.exe" # 后台地理处理
]
def is_whitelisted(self, proc_name):
"""检查进程是否在白名单中"""
return any(white.lower() in proc_name.lower() for white in self.whitelist)
4.2 进程优先级管理
python
def set_process_priority(self, proc, priority='normal'):
"""
设置进程优先级
Args:
proc: 进程对象
priority (str): 优先级 ('low', 'normal', 'high', 'realtime')
"""
try:
priority_map = {
'low': psutil.BELOW_NORMAL_PRIORITY_CLASS,
'normal': psutil.NORMAL_PRIORITY_CLASS,
'high': psutil.HIGH_PRIORITY_CLASS,
'realtime': psutil.REALTIME_PRIORITY_CLASS
}
if priority in priority_map:
proc.nice(priority_map[priority])
self.logger.info(f"✅ 设置进程优先级: {priority}")
except Exception as e:
self.logger.error(f"❌ 设置进程优先级失败: {e}")
4.3 进程依赖关系检查
python
def check_process_dependencies(self, proc):
"""
检查进程依赖关系
Args:
proc: 进程对象
Returns:
list: 依赖进程列表
"""
try:
children = proc.children(recursive=True)
parents = [proc.parent()] if proc.parent() else []
return {
'children': children,
'parents': parents,
'total_dependencies': len(children) + len(parents)
}
except Exception as e:
self.logger.error(f"❌ 检查进程依赖关系失败: {e}")
return {'children': [], 'parents': [], 'total_dependencies': 0}
5. 配置管理和用户界面
5.1 配置文件支持
python
import json
import os
class ConfigManager:
def __init__(self, config_file="arcgis_config.json"):
self.config_file = config_file
self.default_config = {
"check_interval": 5,
"log_file": "arcgis_manager.log",
"target_processes": [
"ArcGISIndexingServer",
"ArcGISPro",
"ArcMap"
],
"whitelist": [
"ArcGISPro.exe"
],
"memory_threshold_mb": 2048,
"enable_memory_monitoring": True,
"enable_dependency_check": True
}
self.config = self.load_config()
def load_config(self):
"""加载配置文件"""
if os.path.exists(self.config_file):
try:
with open(self.config_file, 'r', encoding='utf-8') as f:
config = json.load(f)
return {**self.default_config, **config}
except Exception as e:
print(f"❌ 加载配置文件失败: {e}")
return self.default_config
else:
self.save_config(self.default_config)
return self.default_config
def save_config(self, config=None):
"""保存配置文件"""
config = config or self.config
try:
with open(self.config_file, 'w', encoding='utf-8') as f:
json.dump(config, f, indent=4, ensure_ascii=False)
except Exception as e:
print(f"❌ 保存配置文件失败: {e}")
5.2 命令行参数支持
python
import argparse
def parse_arguments():
"""解析命令行参数"""
parser = argparse.ArgumentParser(description='ArcGIS Pro 进程管理器')
parser.add_argument('--interval', '-i', type=int, default=5,
help='检查间隔时间(秒)')
parser.add_argument('--log-file', '-l', type=str, default='arcgis_manager.log',
help='日志文件名')
parser.add_argument('--config', '-c', type=str, default='arcgis_config.json',
help='配置文件路径')
parser.add_argument('--once', action='store_true',
help='只执行一次检查,不持续监控')
parser.add_argument('--dry-run', action='store_true',
help='模拟运行,不实际终止进程')
parser.add_argument('--verbose', '-v', action='store_true',
help='详细输出')
return parser.parse_args()
6. 实际应用案例
6.1 场景一:开发环境进程清理
python
# 开发环境配置
dev_config = {
"check_interval": 3, # 更频繁的检查
"target_processes": ["ArcGISIndexingServer"],
"whitelist": ["ArcGISPro.exe"],
"memory_threshold_mb": 1024, # 1GB 阈值
"enable_memory_monitoring": True
}
# 创建管理器实例
manager = ArcGISProcessManager(**dev_config)
manager.run()
6.2 场景二:生产环境监控
python
# 生产环境配置
prod_config = {
"check_interval": 30, # 较长的检查间隔
"target_processes": ["ArcGISIndexingServer", "ArcMap"],
"whitelist": ["ArcGISPro.exe", "ArcGISProBackgroundGP.exe"],
"memory_threshold_mb": 4096, # 4GB 阈值
"enable_dependency_check": True
}
# 创建管理器实例
manager = ArcGISProcessManager(**prod_config)
manager.run()
6.3 场景三:批处理脚本集成
python
# 集成到现有工作流
def cleanup_arcgis_processes():
"""清理 ArcGIS 进程的辅助函数"""
manager = ArcGISProcessManager(check_interval=1)
processes = manager.find_arcgis_processes()
if processes:
print(f"发现 {len(processes)} 个 ArcGIS 进程")
for proc_info in processes:
if manager.kill_process(proc_info):
print(f"✅ 已终止: {proc_info['name']} (PID: {proc_info['pid']})")
else:
print("ℹ️ 未发现 ArcGIS 进程")
# 在数据处理流程中调用
if __name__ == "__main__":
# 数据处理前清理
cleanup_arcgis_processes()
# 执行数据处理
# process_data()
# 数据处理后清理
cleanup_arcgis_processes()
7. 性能优化和最佳实践
7.1 性能优化策略
python
class OptimizedArcGISManager(ArcGISProcessManager):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.process_cache = {}
self.cache_ttl = 30 # 缓存30秒
self.last_cache_update = 0
def find_arcgis_processes_cached(self):
"""使用缓存的进程查找"""
current_time = time.time()
# 检查缓存是否有效
if (current_time - self.last_cache_update) < self.cache_ttl:
return self.process_cache.get('processes', [])
# 更新缓存
processes = self.find_arcgis_processes()
self.process_cache['processes'] = processes
self.last_cache_update = current_time
return processes
7.2 错误处理和恢复
python
def robust_process_management(self):
"""健壮的进程管理"""
max_retries = 3
retry_count = 0
while retry_count < max_retries:
try:
self.check_and_kill()
retry_count = 0 # 重置重试计数
except Exception as e:
retry_count += 1
self.logger.error(f"❌ 进程管理出错 (重试 {retry_count}/{max_retries}): {e}")
if retry_count >= max_retries:
self.logger.critical("❌ 达到最大重试次数,停止监控")
break
time.sleep(5) # 等待5秒后重试
7.3 资源监控和告警
python
def monitor_system_resources(self):
"""监控系统资源使用情况"""
try:
# CPU 使用率
cpu_percent = psutil.cpu_percent(interval=1)
# 内存使用率
memory = psutil.virtual_memory()
# 磁盘使用率
disk = psutil.disk_usage('/')
# 检查资源使用情况
if cpu_percent > 80:
self.logger.warning(f"⚠️ CPU 使用率过高: {cpu_percent}%")
if memory.percent > 85:
self.logger.warning(f"⚠️ 内存使用率过高: {memory.percent}%")
if disk.percent > 90:
self.logger.warning(f"⚠️ 磁盘使用率过高: {disk.percent}%")
except Exception as e:
self.logger.error(f"❌ 监控系统资源失败: {e}")
8. 部署和运维
8.1 Windows 服务部署
python
# windows_service.py
import win32serviceutil
import win32service
import win32event
class ArcGISManagerService(win32serviceutil.ServiceFramework):
_svc_name_ = "ArcGISProcessManager"
_svc_display_name_ = "ArcGIS Process Manager"
_svc_description_ = "自动监控和管理 ArcGIS 相关进程"
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
self.manager = None
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
if self.manager:
self.manager.running = False
def SvcDoRun(self):
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
self.manager = ArcGISProcessManager()
self.manager.run()
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(ArcGISManagerService)
8.2 Docker 容器化部署
dockerfile
# Dockerfile
FROM python:3.9-slim
WORKDIR /app
# 安装依赖
COPY requirements.txt .
RUN pip install -r requirements.txt
# 复制源代码
COPY . .
# 设置环境变量
ENV PYTHONUNBUFFERED=1
# 运行脚本
CMD ["python", "arcgis_killer.py"]
8.3 监控和告警集成
python
# 集成 Prometheus 监控
from prometheus_client import Counter, Histogram, Gauge, start_http_server
class PrometheusArcGISManager(ArcGISProcessManager):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Prometheus 指标
self.processes_killed = Counter('arcgis_processes_killed_total',
'Total number of ArcGIS processes killed')
self.process_check_duration = Histogram('arcgis_process_check_duration_seconds',
'Time spent checking processes')
self.active_processes = Gauge('arcgis_active_processes',
'Number of active ArcGIS processes')
# 启动 Prometheus 服务器
start_http_server(8000)
def check_and_kill(self):
with self.process_check_duration.time():
super().check_and_kill()
9. 总结和展望
9.1 技术总结
本文介绍了一个完整的 ArcGIS Pro 进程管理解决方案,具有以下特点:
- 自动化监控:持续监控系统进程,自动检测 ArcGIS 相关进程
- 智能终止策略:优雅终止 + 强制终止的双重保障
- 内存管理:监控进程内存使用,防止内存泄漏
- 配置灵活:支持配置文件、命令行参数等多种配置方式
- 日志完整:详细的日志记录,便于问题排查
- 扩展性强:支持插件化扩展,易于定制
9.2 应用价值
- 提高效率:自动化处理,减少手动操作
- 稳定可靠:健壮的错误处理和恢复机制
- 资源优化:智能内存管理,提高系统性能
- 运维友好:完整的监控和日志系统