使用task.run()在后台任务中运行HttpListener是个好主意吗



我正在与HttpListener作斗争,并等待它的上下文。有时我真的很困惑。我有运行此服务器的应用程序。然而,我不想等待这些请求。我想在后台运行服务器,并不关心它。但我不确定这是否是个好主意,因为微软说,如果你有类似I/O操作的东西,应该等待它。但我不想等待。如果我想在控制台上写点什么呢?我不能,因为我在等待HttpListener的上下文。解决方案看起来很简单:

// _server is an instance of HttpListener
public void StartServer()
{
_server.Prefixes.Add("http://127.0.0.1:8080/test/");
_server.Start();
Task.Run(async() => 
{
while (_server.IsListening)
{
HttpListenerContext context = await _server.GetContextAsync();
await HandleContextAsync(context);
}
}).ConfigureAwait(false);
}

然而,在这种情况下,我不确定是否会出现任何死锁或其他情况,因为处理上下文需要大量操作(例如,它在某个地方打开一个DB连接)。

我决定做的最后一件事是将我的主应用程序和服务器端分开,但我仍然希望在后台运行服务器,以便能够使用控制台的一些输入来停止它。我该怎么办?

我也试过这样的东西:

Task serverListener = server.StartServerAsync();
Console.ReadLine();
await server.StopServerAsync();
//
// The server methods:
//
public async Task StartServerAsync()
{
_server.Prefixes.Add("http://127.0.0.1:8080/test/");
_server.Start();
while (_server.IsListening)
{
HttpListenerContext context = await _server.GetContextAsync();
await HandleContextAsync(context);
}
}
public Task StopServerAsync()
{
_server.Stop();
_server.Close();
return Task.CompletedTask;
}

但在这种情况下,我不确定Task会发生什么,因为它没有被取消或其他什么。服务器已停止,但任务仍然不可用。它是否比Task.Run()的第一种情况更好?

首先,我建议使用像Kestrel这样已经构建好的解决方案。如果您构建自己的解决方案,您将需要做出一些决定,并自己编写大量代码。

微软表示,如果您有类似I/O操作的操作,应该等待。但我不想等它。

这是一般规则,是的。有两个原因:

  1. 通过awaiting,您的应用程序知道操作何时完成。如果你的应用程序不知道何时完成,那么它就不知道何时可以安全退出
  2. 通过awaiting,您的应用程序可以检测并响应所有异常

我不确定不会有任何死锁或

死锁在这里不是问题。假设是Console应用程序,那么默认情况下,所有的延续都将在线程池上运行。注意:ConfigureAwait(false)在您发布的代码中没有做任何事情;ConfigureAwait配置await,但没有await。在控制台应用程序的情况下,ConfigureAwait(false)与根本没有它是一样的。

我仍然希望在后台运行服务器,以便能够使用控制台的一些输入来停止它。

您可以使用Task.Run启动它,并将结果保存在Task变量中,然后在应用程序结束时保存该变量await。或者如果你想要一个";顶层循环";任务,然后让代码中。Task.Run使用顶级try/catch并以这种方式报告错误。

你还需要考虑你希望你的关机有多干净。大多数web服务器在被请求退出时不会立即退出;它们允许任何未完成的请求完成(并关闭它们的侦听套接字,这样就不会有新的请求进入)。如果您希望确保干净的关机,您可能希望await该任务。

此外,您当前的代码有一个";顶层循环";任务,但在侦听下一个连接之前,它会处理每个连接。对于web或TCP/IP服务器来说,这是非常不寻常的行为;对于每个连接来说,启动其自己的"是正常的;顶层循环";以处理每个请求,从而不会阻止其他传入请求。如果你想要一个干净的关闭,这自然会使你需要编写的关闭逻辑复杂化(你现在必须管理一个监听器一个连接集合)。

或者你可以使用Kestrel,它为你做这一切。:)

如果你真的想自己做,你可能会发现我正在入侵的一个新图书馆很有趣。它是专门设计来帮助处理这些";顶级循环";以更结构化的方式。不过,目前它处于一个非常早期的预发布alpha状态。

然而,在这种情况下,我不确定是否会出现任何死锁或

不,这不会引入任何死锁(除了已经存在的死锁(如果有的话))。CCD_ 17在线程池上调度代码的执行;流动;CCD_ 18,这是几种类型的异步相关死锁的臭名昭著的原因。

我也尝试过这样的东西:但在这种情况下,我不确定Task会发生什么,因为它没有被取消或其他什么。

操作系统将处理关闭时应用程序所请求的所有资源的清理。由于侦听器被停止,StartServerAsync任务本身将被设置为具有异常结果,但由于没有等待,因此不会观察到异常(尽管我认为在这种情况下这是可以的),仅此而已

阅读更多:

  • 斯蒂芬·克利里的《不要阻塞异步代码》
  • ExecutionContext与SynchronizationContext——如果你真的想深入了解的话

相关内容

  • 没有找到相关文章

最新更新