1 回答
TA贡献1802条经验 获得超6个赞
好的,现在清楚多了。好吧,理想情况下,您应该从一些有关 Windows 服务的构成的教程开始 - 我打赌这可能已经为您解决了问题。但无论如何我们还是要尝试一下。
一些理论
Windows 服务有两个方面:它执行一些有用的任务并与SCM 设施进行通信。当您使用命令或通过控制面板操作服务时sc
,您可以使用该软件代表您与 SCM 进行对话,而 SCM 则与该服务进行对话。
SCM 和服务使用的确切协议是低级且复杂的,您使用的 Go 包的目的是向您隐藏这种复杂性,并为这些东西提供一个合理的以 Go 为中心的接口。
正如您可能从自己的示例中了解到的那样,Execute
您创建的类型的方法在很大程度上与与 SCM 的通信有关:它运行一个无限for
循环,在每次迭代时都会休眠从r
通道读取数据,并且该通道将 SCM 命令传送到您的服务。
所以你基本上拥有了所谓的“SCM 命令处理循环”。
现在回想一下上面的两个方面。您已经拥有其中之一:您的服务与 SCM 交互,因此您需要另一个 — 实际执行有用任务的代码。
事实上,它已经部分存在:您获取的示例代码创建了一个时间行情指示器,它提供了一个通道,当另一个时间行情通过时,它在该通道上传递值。for
该方法中的循环也Execute
从该通道读取数据,每次发出另一个刻度信号时都会“工作”。
好吧,这对于一个玩具示例来说很好,但对于真正的作品来说却很糟糕。
接近解决方案
因此,让我们暂停一下并考虑一下我们的需求。
我们需要一些代码来运行并执行我们的实际任务。
我们需要现有的命令处理循环才能继续工作。
我们需要这两段代码同时工作。
在这个玩具示例中,第三点是“免费”的,因为时间计时器自动执行等待下一个计时的任务,并且与其余代码完全并发。
你真正的代码很可能不会有那么奢侈,那么你该怎么办?
在 Go 中,当你需要同时做某件事和其他事情时,一个明显的答案是“使用 goroutine”。
因此,第一步是获取现有代码,将其转换为可调用函数,然后在进入循环之前在单独的 goroutine 中调用它for
。这样,您将同时运行两个部分。
困难的部分
好吧,那并不难。
困难的部分是:
如何配置执行任务的代码。
如何使单片机命令处理循环和执行任务的代码进行通信。
配置
这实际上取决于您的 $dayjob 或 $current_project 的政策,但有一些提示:
Windows 服务可以接收命令行参数——无论是单次运行还是永久(在每次运行时传递给服务)。
缺点是从 UI/UX 的角度来看使用它们并不方便。
通常 Windows 服务用于读取注册表。
如今(在 .NET 及其普遍的 xml-ity 出现之后)服务倾向于读取配置文件。
大多数时候,操作系统环境并不适合该任务。
您可以合并其中几个场地。
我想我会从配置文件开始,但话又说回来,我认为你应该选择阻力最小的路径。
需要记住的一件事是,配置的读取和处理最好在服务向 SCM 发出它已启动的信号之前完成:如果配置无效或无法加载,服务应广泛记录该情况并发出信号失败,并且不运行实际的任务处理代码。
命令处理循环和携带代码的任务之间的通信
在我看来,这是最难的部分。
在这里写一整本书是可能的,但现在让我们保持简单。
为了使其尽可能简单,我会执行以下操作:
考虑暂停、停止和关闭几乎相同:所有这些信号都必须告诉您的任务处理代码退出,然后等待它实际执行此操作。
将“继续”信号视为与启动任务处理函数相同:在新的 goroutine 中再次运行它。
进行单向通信:从控制循环到任务处理代码,而不是其他方式 - 这将大大简化服务状态管理。
这样,您可以创建一个任务处理代码侦听或定期检查的通道,当一个值来自该通道时,代码停止运行,关闭通道并退出。
当 SCM 告诉控制循环暂停、停止或关闭时,控制循环会在该通道上发送任何内容,然后等待其关闭。当发生这种情况时,它知道任务处理代码已完成。
在 Go 中,仅用于信令的通道的范例是具有类型struct{}
(空struct
)的通道。
如何在运行代码的任务中监视此控制通道的问题是一个开放的问题,并且在很大程度上取决于它执行的任务的性质。
这里的任何进一步帮助都可以背诵 Go 书籍中有关并发的内容,因此您应该首先了解这一点。
还有一个有趣的问题是如何使控制循环和任务处理循环之间的通信能够适应后者可能出现的处理停顿,但话又说回来,在我看来,现在讨论这个问题还为时过早。
- 1 回答
- 0 关注
- 135 浏览
添加回答
举报