如何在Windows中将Python脚本作为服务运行?

346 投票
14 回答
455082 浏览
提问于 2025-04-10 23:50

我正在设计一个程序架构,这些程序会共享一些存储在数据库中的相关对象。我希望其中一个程序能作为一个服务,提供一个更高级的接口来操作这些对象,而其他程序则通过这个服务来访问这些对象。

我目前打算使用Python和Django框架来实现这个服务。我对如何在Linux上将Python程序变成守护进程(也就是后台运行)有一定了解。不过,系统还需要支持Windows,这部分我经验不多,对Windows编程几乎没有了解,更别提Windows服务了。

请问,能否将Python程序作为Windows服务运行(也就是说,能够在没有用户登录的情况下自动运行)?我不一定需要实现这个功能,但我需要大概了解一下怎么做,以便决定是否要朝这个方向设计。

编辑:感谢大家到目前为止的回答,内容很全面。我还想知道一件事:Windows是如何知道我的服务的?我可以用Windows自带的工具来管理它吗? 在Windows中,类似于在/etc/init.d放置启动/停止脚本的做法是什么?

14 个回答

53

虽然我几周前给了那个被选中的答案一个赞,但这段时间我在这个话题上遇到了更多的困难。我觉得用一个特别的Python安装和一些特殊模块来把脚本当服务运行,简直就是走错了路。那可移植性怎么办呢?

我偶然发现了一个很棒的工具叫做Non-sucking Service Manager,它让处理Windows服务变得简单又合理。我想,既然我可以给一个已安装的服务传递选项,那我就可以选择我的Python可执行文件,并把我的脚本作为一个选项传过去。

我还没有尝试这个解决方案,但我现在就打算试试,并在过程中更新这个帖子。我也对在Windows上使用虚拟环境感兴趣,所以我可能会早晚写个教程,并在这里链接到它。

102

最简单的方法是使用:NSSM - 非吸血鬼服务管理器。 只需下载并解压到你选择的位置。它是一个独立的工具,大小大约300KB(比起为了这个目的安装整个pywin32套件要小得多),而且不需要“安装”。压缩包里有64位和32位两个版本,任意一个在当前系统上都能很好地工作(你可以在64位系统上用32位版本来管理服务)。

图形界面方法

1 - 将Python程序安装为服务。以管理员身份打开命令提示符

c:\>nssm.exe install WinService

2 - 在NSSM的图形界面控制台上:

路径:C:\Python27\Python27.exe

启动目录:C:\Python27

参数:c:\WinService.py

3 - 在services.msc中检查创建的服务

脚本方法(无图形界面)

如果你的服务需要作为自动化、非交互式的程序的一部分,这种方法就很方便,比如批处理或安装脚本。假设这些命令是以管理员权限执行的。

为了方便,这里将命令简单称为nssm.exe。不过,在脚本中最好用它的完整路径c:\path\to\nssm.exe来引用,因为它是一个独立的可执行文件,可能位于系统不认识的私有路径中。

1. 安装服务

你必须指定服务的名称、正确的Python可执行文件的路径,以及脚本的路径:

nssm.exe install ProjectService "c:\path\to\python.exe" "c:\path\to\project\app\main.py"

更详细地说:

nssm.exe install ProjectService 
nssm.exe set ProjectService Application "c:\path\to\python.exe"
nssm.exe set ProjectService AppParameters "c:\path\to\project\app\main.py"

另外,你可能希望你的Python应用作为一个Python模块启动。一个简单的方法是告诉nssm它需要切换到正确的启动目录,就像你在命令行中启动时那样:

nssm.exe install ProjectService "c:\path\to\python.exe" "-m app.main"
nssm.exe set ProjectService AppDirectory "c:\path\to\project"

这种方法在虚拟环境和独立(嵌入式)Python安装中效果很好。只需确保在这些环境中用常规方法正确解决任何路径问题。如果需要,nssm还可以设置环境变量(例如PYTHONPATH),并且可以启动批处理脚本。

2. 启动服务

nssm.exe start ProjectService 

3. 停止服务

nssm.exe stop ProjectService

4. 删除服务,指定confirm参数以跳过交互式确认。

nssm.exe remove ProjectService confirm
301

当然可以。 我是通过使用包含在ActivePython中的pythoncom库来实现的,或者你也可以通过pywin32(Windows的Python扩展)来安装它。

下面是一个简单服务的基本框架:

import win32serviceutil
import win32service
import win32event
import servicemanager
import socket


class AppServerSvc (win32serviceutil.ServiceFramework):
    _svc_name_ = "TestService"
    _svc_display_name_ = "Test Service"

    def __init__(self,args):
        win32serviceutil.ServiceFramework.__init__(self,args)
        self.hWaitStop = win32event.CreateEvent(None,0,0,None)
        socket.setdefaulttimeout(60)

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)

    def SvcDoRun(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                              servicemanager.PYS_SERVICE_STARTED,
                              (self._svc_name_,''))
        self.main()

    def main(self):
        pass

if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(AppServerSvc)

你的代码应该放在main()这个方法里——通常会有一个无限循环,可以通过检查一个标志来中断这个循环,这个标志是在SvcStop方法中设置的。

撰写回答