我在哪里可以在Self Hosted Self Contained ASP.NET Core Microservice
中创建多个长时间运行的后台线程,其生命周期与微服务生命周期相同?因此,从线程检索的信息可以作为对请求的响应发送。
尝试了给定的代码但是当后台线程忙时它会降低http请求性能。 Program.cs文件的主要方法是:
static void Main(string[] args)
{
//Start background thread1
//Start background thread2
//Around 10 background threads
//Start host
var host = new WebHostBuilder()
.UseKestrel()
.UseUrls(ServerUrl)
.UseConfiguration(config)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.ConfigureServices(s => s.AddRouting())
.Configure(app => app.UseRouter(r => { (new Router()).Route(r); }))
.Build();
host.Run();
}
线程以这种方式工作:
Thread t1 = new Thread(StartWork);
t1.IsBackground = true;
t1.Start();
public void StartWork()
{
while (ApplicationIsRunning)
{
//Get database info >> login into remote devices (SSH) >> get information >> process information >> update application variables and database
Thread.Sleep(10000);
}
}
线程繁忙但CPU请求性能非常差时,CPU利用率仅为1-5%。进入睡眠状态再次改善状态。
问题出在SSH客户端连接的连接方法上。在某些时候,connect方法没有响应,它也会影响所有其他线程。那很奇怪!
Renci.SshNet.SshClient sshClient = New Renci.SshNet.SshClient(sshConnectionInfo);
sshClient.Connect();
如果一个线程由于任何原因而忙于连接,则不应影响其他线程。
答案 0 :(得分:6)
public abstract class HostedService : IHostedService
{
private Task _executingTask;
private CancellationTokenSource _cts;
public Task StartAsync(CancellationToken cancellationToken)
{
// Create a linked token so we can trigger cancellation outside of this token's cancellation
_cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
// Store the task we're executing
_executingTask = ExecuteAsync(_cts.Token);
// If the task is completed then return it, otherwise it's running
return _executingTask.IsCompleted ? _executingTask : Task.CompletedTask;
}
public async Task StopAsync(CancellationToken cancellationToken)
{
// Stop called without start
if (_executingTask == null)
{
return;
}
// Signal cancellation to the executing method
_cts.Cancel();
// Wait until the task completes or the stop token triggers
await Task.WhenAny(_executingTask, Task.Delay(-1, cancellationToken));
// Throw if cancellation triggered
cancellationToken.ThrowIfCancellationRequested();
}
// Derived classes should override this and execute a long running method until
// cancellation is requested
protected abstract Task ExecuteAsync(CancellationToken cancellationToken);
}
then you can implement your abstract class:
public class DataRefreshService : HostedService
{
private readonly RandomStringProvider _randomStringProvider;
public DataRefreshService(RandomStringProvider randomStringProvider)
{
_randomStringProvider = randomStringProvider;
}
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
await _randomStringProvider.UpdateString(cancellationToken);
await Task.Delay(TimeSpan.FromSeconds(5), cancellationToken);
}
}
}
在您的设置中,您只需添加依赖项:
services.AddSingleton<IHostedService, DataRefreshService>();
RandomStringProvider
只是一个例子。你得到的照片:))
.net核心为您自动连接,就像一个魅力!完美地保持兔子连接开放!
试一试!答案 1 :(得分:2)
尝试了给定的代码但是当后台线程忙时它会降低http请求性能。
首先要意识到的是,在Web应用程序的上下文中没有真正的后台工作。 Web服务器旨在快速服务请求。有一个线程池,通常由多达1000个线程组成(通常称为服务器的“最大请求”,因为每个请求都需要一个线程)。该线程池是一个有限的资源,当你最大化时,任何进一步的请求都会排队,直到一个线程再次可用。启动新线程会从此池中获取一个线程。因此,您的一个请求现在消耗两个线程而不是一个。做这种类型的东西就足够了,只需要少量的请求就可以轻松耗尽线程池,然后让你的网络服务器瘫痪。
至少如果你正在进行某种异步工作,你可能会允许服务请求的主线程返回到池中,而这个新线程可以做到这一点,但即便如此,你只需要交换一个线程另一个。但是,在这里,你甚至没有这样做。这里的代码是阻塞的,所以当你的线程池已经被饿死时,你现在让线程处于空闲状态。
长短不要这样做。如果需要完成任何需要花费不少时间的工作,那么应该将该工作卸载到后台进程,即在Web应用程序的上下文之外运行的可以执行工作的内容而不会影响您的Web应用程序的性能。您几乎不应该在Web应用程序中创建新线程。如果您发现自己这样做,则需要重新考虑您的设计。