在特定的conda虚拟环境中以Windows服务运行Python程序

2024-04-23 14:28:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图运行一个python程序,用Anaconda编写,作为Windows服务。复杂的是我想从一个特定的conda虚拟环境运行Windows服务。我们的想法是,在未来,我们可能会开发更多基于python的windows服务,这些服务可能有不同的模块依赖关系,因此将每个服务保持在自己的虚拟环境中是理想的。在

我找到了几篇关于python和windows服务优秀的文章。我创建了一个非常简单的测试程序,在服务启动后将一些消息写入文本文件。我可以成功地将这个测试python程序安装为windows服务,并且可以在我的文件中看到各种文本消息。但是,当我尝试将诸如Numpy或TensorFlow之类的模块导入到我的简单测试python程序中时,服务将无法启动,并且我收到了无法找到它们各自的DLL的失败消息。在

我确信问题是因为所需的conda虚拟环境尚未激活。同时,我尝试在系统级别复制各种conda环境变量;尝试将所有必需的python库路径从虚拟环境添加到系统路径和系统范围的python路径,但是没有成功。在

我怀疑,如果能将conda虚拟环境作为python代码的一部分来激活,就可以解决问题了。(我也怀疑在我的基本配置中安装所有必需的模块可以解决问题,但我希望避免这种情况)。在

这是我写的小测试程序。这个程序可以很好地与诸如sys、os等基本Python模块配合使用。当我尝试运行它并包含Numpy或TensorFlow时,它失败并显示以下错误消息: (这是在我尝试并启动我的服务后从Windows事件查看器中获得的-该服务安装正确):

Python无法导入服务的模块 回溯(最近一次呼叫): 文件“D:\TFS\Projects\DEV\AEPEnrollmentForms\src\aepenrl\Windows\u服务_示例.py“,第35行,英寸 将numpy作为np导入 文件“C:\Users\pboerner\AppData\Local\conda\conda\envs\aepenr\lib\site packages\numpy_yuinit_u.py”,第140行,in 从。导入分发服务器初始化 文件“C:\Users\pbooner\AppData\Local\conda\conda\envs\aepenr\lib\site packages\numpy_分发服务器_初始py“,第34行,英寸 从。导入 ImportError:DLL加载失败:找不到指定的模块。 %2: %3个

下面是简单测试程序的代码。(我大部分的Windows服务集成工作都来自Davide Mastromatteo提供的一篇优秀文章)

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)

Tags: 模块thetoimportselfwindowsdefservice