防止 .Net Core 5 控制台应用程序在 Linux 上作为服务在 运行 时结束的推荐方法
Recommended way to prevent a .Net Core 5 console app from ending when run on Linux as a service
我有一个 .Net Core 5 控制台应用程序 运行 在 Linux (Debian 10) 上。基本结构是这样的:
class Program
{
static async Task Main(string[] args)
{
await SetupStuffAsync();
MonitorGpioService.Run();
RunAScheduledServiceOnATimer();
Console.ReadLine();
}
}
基本上,它 运行 在 Orange Pi Zero 上(类似于 Raspberry Pi),等待 GPIO 引脚上的信号。当该信号到达时,它会读取串行端口几毫秒,将数据写入 MariaDB 数据库(使用 EF Core),然后 post 将数据发送到 Web API。它还 运行 每 5 分钟发送一些定期维护代码(使用 System.Timers.Timer())。
这个应用程序 运行 无人看管 - 甚至没有屏幕 - 并且必须 运行 始终,从 Orange Pi 启动到关闭的那一刻。
Console.ReadLine() 当我在开发过程中手动 运行ning 应用程序时,它可以很好地阻止应用程序结束。
但是现在我需要应用程序在 Debian 启动时自动 运行,所以我做了以下操作:
sudo nano /etc/systemd/system/orangePi.service
[Unit]
Description=orangePi.service
[Service]
Type=simple
ExecStart=/root/dotnet/dotnet sr/local/bin/orangePiService/orangePiService.dll
Restart=on-failure
RestartSec=10
KillMode=process
[Install]
WantedBy=multi-user.target
效果很好 - 应用程序会在启动时自动启动,但有一个问题。 Console.ReadLine() 被完全忽略。它从字面上执行所有内容然后结束。我想这是有道理的,因为在这种情况下,控制台中没有 运行ning。
我知道我可以,例如,在最后放一个无限循环以防止它结束:
class Program
{
static async Task Main(string[] args)
{
await SetupStuffAsync();
MonitorGpioService.Run();
RunAScheduledServiceOnATimer();
while (0 == 0) {};
}
}
这很管用,但我不喜欢。它不仅不漂亮,而且我想它会用掉很多 CPU 到 运行 这个循环。
我可以这样做:
class Program
{
static async Task Main(string[] args)
{
await SetupStuffAsync();
MonitorGpioService.Run();
RunAScheduledServiceOnATimer();
while (0 == 0)
{
Thread.Sleep(int.MaxValue);
};
}
}
我认为 CPU 会减轻负担,但我认为它会阻塞此线程。那是问题吗?我知道这取决于其余代码的外观,但这里 post 的代码相当多。我可以说的是,大部分操作都发生在 MonitorGpioService.Run() 中,我在下面以极其简化的格式 posting:
using System.Device.Gpio;
public static class MonitorGpioService()
{
static GpioController _controller;
public static void Run()
{
_controller = new GpioController();
_controller.RegisterCallbackForPinValueChangedEvent((int)Settings.GpioPin.Read, PinEventTypes.Rising, onSignalPinValueChangedEvent);
}
private static void onSignalPinValueChangedEvent(object sender, PinValueChangedEventArgs args)
{
string data = ReadSerialPortFor40ms();
using (var context = new eballContext())
{
await _dbContext.Readings.AddRangeAsync(readings);
await _dbContext.SaveChangesAsync();
}
}
}
我尽可能地使用等待,我认为这不会受到主线程被阻塞的影响。我不确定当 GPIO 引脚状态发生变化时事件处理程序的触发。从我的测试来看,它似乎没有受到阻塞主线程的影响,但我不能确定...
总而言之(对于 post 的篇幅,我深表歉意),我试图弄清楚什么是防止 .Net Core 控制台应用程序在 运行 时退出的最佳方法宁 Linux 作为一项服务。最好的情况是,我的意思是尽可能少地消耗 CPU,或者可能尽可能少地阻塞线程(假设这甚至是一个问题,考虑到我的大部分代码我不太确定运行s on Timers 或 uses waits).
好吧,while 循环是一个美丽的东西,但它是 CPU 的敌人。
而不是 while,我经常使用 ManualResetEvent class 来防止关闭控制台应用程序。
当我在 Docker 上的 Linux 容器中使用此代码块时,通常它会起作用。
我没有实际的代码块,我会记住它;
public static ManualResetEvent _Shutdown = new ManualResetEvent(false);
static void Main(string[] args)
{
//Lots of stuff.
_Shutdown.WaitOne();
}
基本上关机信号永远不会出现,控制台应用程序也永远不会关闭。当然,您可以根据需要开发更有针对性的代码。这可以防止控制台应用程序在所有这些工作正常时关闭。你可以试一试。您还可以在 SO 中找到许多不同的方法。
来自
的答案
In case of async main method, one could also use await Task.Delay(-1);
Task.Delay()
本身通常更优雅,因为它允许您传递取消令牌,从而在需要时启用正常关闭。
Thread.Sleep()
应该也可以,但不能取消。您可以使用 Timeout.Infinite
代替 while 循环来暂停而不会浪费任何周期
我有一个 .Net Core 5 控制台应用程序 运行 在 Linux (Debian 10) 上。基本结构是这样的:
class Program
{
static async Task Main(string[] args)
{
await SetupStuffAsync();
MonitorGpioService.Run();
RunAScheduledServiceOnATimer();
Console.ReadLine();
}
}
基本上,它 运行 在 Orange Pi Zero 上(类似于 Raspberry Pi),等待 GPIO 引脚上的信号。当该信号到达时,它会读取串行端口几毫秒,将数据写入 MariaDB 数据库(使用 EF Core),然后 post 将数据发送到 Web API。它还 运行 每 5 分钟发送一些定期维护代码(使用 System.Timers.Timer())。
这个应用程序 运行 无人看管 - 甚至没有屏幕 - 并且必须 运行 始终,从 Orange Pi 启动到关闭的那一刻。
Console.ReadLine() 当我在开发过程中手动 运行ning 应用程序时,它可以很好地阻止应用程序结束。 但是现在我需要应用程序在 Debian 启动时自动 运行,所以我做了以下操作:
sudo nano /etc/systemd/system/orangePi.service
[Unit]
Description=orangePi.service
[Service]
Type=simple
ExecStart=/root/dotnet/dotnet sr/local/bin/orangePiService/orangePiService.dll
Restart=on-failure
RestartSec=10
KillMode=process
[Install]
WantedBy=multi-user.target
效果很好 - 应用程序会在启动时自动启动,但有一个问题。 Console.ReadLine() 被完全忽略。它从字面上执行所有内容然后结束。我想这是有道理的,因为在这种情况下,控制台中没有 运行ning。
我知道我可以,例如,在最后放一个无限循环以防止它结束:
class Program
{
static async Task Main(string[] args)
{
await SetupStuffAsync();
MonitorGpioService.Run();
RunAScheduledServiceOnATimer();
while (0 == 0) {};
}
}
这很管用,但我不喜欢。它不仅不漂亮,而且我想它会用掉很多 CPU 到 运行 这个循环。
我可以这样做:
class Program
{
static async Task Main(string[] args)
{
await SetupStuffAsync();
MonitorGpioService.Run();
RunAScheduledServiceOnATimer();
while (0 == 0)
{
Thread.Sleep(int.MaxValue);
};
}
}
我认为 CPU 会减轻负担,但我认为它会阻塞此线程。那是问题吗?我知道这取决于其余代码的外观,但这里 post 的代码相当多。我可以说的是,大部分操作都发生在 MonitorGpioService.Run() 中,我在下面以极其简化的格式 posting:
using System.Device.Gpio;
public static class MonitorGpioService()
{
static GpioController _controller;
public static void Run()
{
_controller = new GpioController();
_controller.RegisterCallbackForPinValueChangedEvent((int)Settings.GpioPin.Read, PinEventTypes.Rising, onSignalPinValueChangedEvent);
}
private static void onSignalPinValueChangedEvent(object sender, PinValueChangedEventArgs args)
{
string data = ReadSerialPortFor40ms();
using (var context = new eballContext())
{
await _dbContext.Readings.AddRangeAsync(readings);
await _dbContext.SaveChangesAsync();
}
}
}
我尽可能地使用等待,我认为这不会受到主线程被阻塞的影响。我不确定当 GPIO 引脚状态发生变化时事件处理程序的触发。从我的测试来看,它似乎没有受到阻塞主线程的影响,但我不能确定...
总而言之(对于 post 的篇幅,我深表歉意),我试图弄清楚什么是防止 .Net Core 控制台应用程序在 运行 时退出的最佳方法宁 Linux 作为一项服务。最好的情况是,我的意思是尽可能少地消耗 CPU,或者可能尽可能少地阻塞线程(假设这甚至是一个问题,考虑到我的大部分代码我不太确定运行s on Timers 或 uses waits).
好吧,while 循环是一个美丽的东西,但它是 CPU 的敌人。 而不是 while,我经常使用 ManualResetEvent class 来防止关闭控制台应用程序。 当我在 Docker 上的 Linux 容器中使用此代码块时,通常它会起作用。 我没有实际的代码块,我会记住它;
public static ManualResetEvent _Shutdown = new ManualResetEvent(false);
static void Main(string[] args)
{
//Lots of stuff.
_Shutdown.WaitOne();
}
基本上关机信号永远不会出现,控制台应用程序也永远不会关闭。当然,您可以根据需要开发更有针对性的代码。这可以防止控制台应用程序在所有这些工作正常时关闭。你可以试一试。您还可以在 SO 中找到许多不同的方法。
来自
In case of async main method, one could also use
await Task.Delay(-1);
Task.Delay()
本身通常更优雅,因为它允许您传递取消令牌,从而在需要时启用正常关闭。
Thread.Sleep()
应该也可以,但不能取消。您可以使用 Timeout.Infinite
代替 while 循环来暂停而不会浪费任何周期