C# 建议/接受在新线程中运行异步void方法吗?
我有一段旧代码(.NET 3.5),其中我在一个单独的线程中运行新TcpClient的注册: 旧代码: 此代码的目标是避免在等待新客户端时阻塞应用程序。我正在将此代码移植到.NET标准,我想知道是否必须使用.NET的新功能 我说的是C# 建议/接受在新线程中运行异步void方法吗?,c#,multithreading,async-await,task,C#,Multithreading,Async Await,Task,我有一段旧代码(.NET 3.5),其中我在一个单独的线程中运行新TcpClient的注册: 旧代码: 此代码的目标是避免在等待新客户端时阻塞应用程序。我正在将此代码移植到.NET标准,我想知道是否必须使用.NET的新功能 我说的是async/await和Task 异步线程版本 由于这个线程将持续整个应用程序的时间,我首先考虑用新的异步方法简单地替换实际方法。但如果我这样做,我会得到一个运行async void方法的新线程: public class TcpServer { privat
async/await
和Task
异步线程版本
由于这个线程将持续整个应用程序的时间,我首先考虑用新的异步方法简单地替换实际方法。但如果我这样做,我会得到一个运行async void
方法的新线程:
public class TcpServer
{
private readonly TcpListener _tcpListener;
public TcpServer(int port)
{
_tcpListener = new TcpListener(IPAddress.Any, port);
}
public void StartListening()
{
_tcpListener.Start();
var t = new Thread(new ThreadStart(AcceptConnectionsAsync));
t.Start();
}
private async void AcceptConnectionsAsync()
{
while (true)
{
var client = await _tcpListener.AcceptTcpClientAsync();
// Some stuff
}
}
}
不建议编写async void
方法,除非在极少数情况下(如事件处理程序)
这种情况可以接受吗?
异步任务版本
作为一个新选项,我在任务中运行注册:
public class TcpServer
{
private readonly TcpListener _tcpListener;
public TcpServer(int port)
{
_tcpListener = new TcpListener(IPAddress.Any, port);
}
public Task StartListeningAsync()
{
_tcpListener.Start();
return Task.Run(async () => await AcceptConnectionsAsync());
}
private async Task AcceptConnectionsAsync()
{
while (true)
{
var client = await _tcpListener.AcceptTcpClientAsync();
// Some stuff
}
}
}
使用此代码,只要我不wait
acceptconnectionasync
调用,应用程序就不会被阻止(我使用while(true)
简化代码,但我正确处理应用程序的关闭和监听的结束,我可以在那里调用wait,甚至可以触发并忘记它)
但是正如我所说的,这个操作应该持续整个应用程序的时间,我认为一个新线程更合适(至少在架构方面,但也在效率方面)
我错了吗?
不要对代码的这一部分进行任何更改
这是我看到的最后一个选择。我打算用Async/Await
更新代码,因为我读到Async/Await提高了TcpListener的性能
但这是真的吗?
重要信息
以下是一些我认为相关的信息。不要犹豫询问更多细节
- 运行此代码的应用程序是一个控制台应用程序。我知道这对于异步/等待上下文很重要
方法为每个新连接运行一个新任务(这些任务是短期的,类型为fire和forget)AcceptConnections(Async)
- 主线程执行大量计算。最好的解决方案是对主线程性能的影响最小
- 还有一个线程的行为与此类似(相同的持续时间),负责侦听来自所有客户端的数据。我打算应用与此相同的操作
创建一个新线程只是为了调用一个异步方法,就像雇佣一个人到你家来帮你把一封信放进邮箱一样。这不仅仅是你自己做的工作,因为把信送到目的地的实际行动实际上并不会阻止你做一些琐碎工作以外的工作来开始它。
这种情况可以接受吗?
它是一个事件处理程序吗?为什么要使用异步无效
而不是异步任务
?有帮助吗?因为ThreadStart
构造函数只接受返回void
的委托。为什么要使用ThreadStart
vs任务
?在我的研究中找不到您的链接。。。太糟糕了,它回答了我问题的一部分。关于你的第二个问题,我读到任务
不适用于长期行动。这就是我希望使用线程
的原因。请参阅@fharraauit,它是整个acceptconnectionasync
方法,其持续时间与应用程序相同。调用AcceptTcpClientAsync
在foreach循环中。@fharreau该方法将在相当一段时间内异步工作。当然,只要应用程序还在运行,就有可能。但该方法立即返回。您在另一个线程中实际运行的唯一工作是启动操作的少量工作。其余的都没有受到任何影响。我明白你的意思。我不能在主线程中等待该调用,因为我需要在该线程中执行其他操作(并且我需要为每个新连接等待它)。这就是我最初在一个新线程中使用阻塞调用运行该方法的原因。可能我就是不能在我的情况下使用Async/Await?@fharreau如果你不想在方法永远无法完成后运行其余的代码,那么就不要Await
itawait
只是编写异步方法完成时运行的代码的一种简单方法。您不需要创建一个新线程来不等待某些东西。在这种情况下,在var client=await\u tcpListener.AcceptTcpClientAsync()之后的代码在哪里执行
在acceptconnectionasync
方法中?在另一个线程中?因为这段代码是一个永久循环,所以它不会影响主线程的性能?
public class TcpServer
{
private readonly TcpListener _tcpListener;
public TcpServer(int port)
{
_tcpListener = new TcpListener(IPAddress.Any, port);
}
public Task StartListeningAsync()
{
_tcpListener.Start();
return Task.Run(async () => await AcceptConnectionsAsync());
}
private async Task AcceptConnectionsAsync()
{
while (true)
{
var client = await _tcpListener.AcceptTcpClientAsync();
// Some stuff
}
}
}