Pee*_*eer 5 python windows-services
我正在尝试运行一个使用 Anaconda 编写的 python 程序作为 Windows 服务。复杂的是我想从特定的 conda 虚拟环境运行 Windows 服务。这个想法是在未来,我们可能会开发更多基于 python 的 Windows 服务,这些服务可能具有不同的模块依赖关系,因此将每个服务保持在自己的虚拟环境中将是理想的。
我找到了几篇关于如何将 python 程序编写为 Windows 服务的优秀文章,它们运行良好。我创建了一个非常简单的测试程序,它只是在服务启动后将一些消息写入文本文件。我可以成功地将这个测试 python 程序安装为 Windows 服务,并且我在我的文件中看到了各种文本消息。但是,当我尝试将 Numpy 或 TensorFlow 等模块导入到我的简单测试 Python 程序中时,该服务将无法启动,并且我收到无法找到它们各自 DLL 的失败消息。
我确定问题是因为所需的 conda 虚拟环境尚未激活。同时,我尝试在系统级别复制各种 conda 环境变量;尝试将所有必需的python库路径从虚拟环境添加到系统路径和系统范围的python路径,但无济于事。
我怀疑如果我可以激活 conda 虚拟环境作为我的 python 代码的一部分,那将解决问题。(我还怀疑将所有必需的模块安装到我的基本配置中会解决问题,但我想避免这种情况)。
这是我编写的小测试程序。该程序与基本的 Python 模块(如 sys、os 等)一起工作得很好。当我尝试运行它并包含 Numpy 或 TensorFlow 时,它失败并显示以下错误消息:(这是我尝试启动服务后的 Windows 事件查看器 - 安装正确):
Python 无法导入服务的模块 Traceback(最近一次调用最后一次):文件 "D:\TFS\Projects\DEV\AEPEnrollmentForms\src\aepenrl\Windows_Service_Example.py",第 35 行,在 import numpy as np File "C:\ Users\pboerner\AppData\Local\conda\conda\envs\aepenr\lib\site-packages\numpy__init__.py”,第 140 行,来自 . 导入 _distributor_init 文件“C:\Users\pboerner\AppData\Local\conda\conda\envs\aepenr\lib\site-packages\numpy_distributor_init.py”,第 34 行,从 . 导入 _mklinit 导入错误:DLL 加载失败:找不到指定的模块。%2: %3
这是简单测试程序的代码。(我从 Davide Mastromatteo 提供的一篇优秀文章中获取的大部分 Windows 服务集成工作)
import numpy as np
import socket
import sys
import time
import win32serviceutil
import servicemanager
import win32event
import win32service
class SimpleService(win32serviceutil.ServiceFramework):
'''Base class to create winservice in Python'''
_svc_name_ = 'TestPythonSrvc'
_svc_display_name_ = 'Test Python Service'
_svc_description_ = 'Test to see how to create a windows service with python'
@classmethod
def parse_command_line(cls):
'''
ClassMethod to parse the command line
'''
win32serviceutil.HandleCommandLine(cls)
def __init__(self, args):
'''
Constructor of the winservice
'''
self.isrunning=True
self.fid = open("D:\\temp\\simple_service.txt", "w")
self.fid.write("Initialize\n")
self.fid.flush()
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
socket.setdefaulttimeout(60)
def SvcStop(self):
'''
Called when the service is asked to stop
'''
self.stop()
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
'''
Called when the service is asked to start
'''
self.start()
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
self.main()
def start(self):
'''
Override to add logic before the start
eg. running condition
'''
self.isrunning = True
self.fid.write("Start method called\n")
self.fid.flush()
def stop(self):
'''
Override to add logic before the stop
eg. invalidating running condition
'''
self.isrunning = False
self.fid.write("STOP method called. Setting stop flag\n")
self.fid.flush()
def main(self):
'''
Main class to be ovverridden to add logic
'''
a = np.zeros((100,1))
while True:
if self.isrunning:
self.fid.write(f"Tick. Numpy array shape {a.shape}\n")
self.fid.flush()
time.sleep(1)
else:
self.fid.write("Breaking out of main loop\n")
self.fid.flush()
break;
self.fid.write("Closing the log file\n")
self.fid.flush()
self.fid.close()
if __name__ == '__main__':
# This code block was required to get this simple service example to run
# on a Windows 10 laptop with Admin privs. Only calling the
# HandleCommandLine method alone didn'd seem to work. Not sure why but this
# code was provided as a solution on the Web.
if len(sys.argv) == 1:
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(SimpleService)
servicemanager.StartServiceCtrlDispatcher()
else:
win32serviceutil.HandleCommandLine(SimpleService)
Run Code Online (Sandbox Code Playgroud)
不幸的是,Windows 的服务管理器并不像 systemd 那样灵活。我发现的唯一方法是执行以下操作:
call C:\ProgramData\Anaconda3\Scripts\activate.bat C:\ProgramData\Anaconda3
call activate yourenv
cd C:/path/to/your/wd
python yourservice.py and your args
Run Code Online (Sandbox Code Playgroud)
注意:您的 activate.bat 文件可能位于您的主文件夹下:~\AppData\local\Continuum\anaconda3\Scripts这可以bokeh很好地为服务器提供服务(使用bokeh serve而不是python)。我想它适用于任何复杂的 python 脚本。
您可以在“挂钩”选项卡中停止或退出时运行命令。
就我而言,批处理文件中的逻辑取决于机器,因此我需要制作一个额外的 python 脚本,在设置写入批处理文件时调用该脚本。
| 归档时间: |
|
| 查看次数: |
990 次 |
| 最近记录: |