是否建议/可以在新线程中运行异步void方法?

时间:2018-06-20 13:55:07

标签: c# multithreading async-await task

我有一段旧代码(.NET 3.5),我在一个单独的线程中运行新TcpClient的注册:

旧代码:

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(AcceptConnections));
        t.Start();
    }

    private void AcceptConnections()
    {
        while (true)
        {
            var client = _tcpListener.AcceptTcpClient();

            // Some stuff
        }
    }
}

此代码的目标是避免在等待新客户端时阻止应用程序。我正在将此代码移植到.NET Standard,我想知道是否必须使用.NET的新功能。

我正在谈论async/awaitTask

异步线程版本

由于该线程将与整个应用程序一样长,因此我首先考虑用新的异步方法简单地替换实际方法。但是,如果这样做,我最终得到一个运行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方法。

这种情况可以接受吗?

异步任务版本

作为一个新选项,我在Task中运行注册:

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
        }
    }
}

使用此代码,只要我不await进行AcceptConnectionsAsync调用,就不会阻止该应用程序(我使用while(true)简化了代码,但是我处理了应用程序,并且听音结束正常,我可以在那叫await甚至开火然后忘记它。

但是,正如我所说的那样,该操作应该持续整个应用程序的时间,我认为一个新的线程更合适(就架构而言,至少在效率方面)。

我错了吗?

请勿对代码的这一部分进行任何更改

这是我看到的最后一个选项。我打算用Async/Await更新代码,因为我读到异步/等待可以提高TcpListener的性能。

但这是真的吗?

重要信息

以下是一些我认为可能相关的信息。不要犹豫,要求进一步的细节。

  • 运行此代码的应用程序是控制台应用程序。我知道这对于异步/等待上下文可能很重要?
  • AcceptConnections(Async)方法为每个新连接运行一个新的Task(这些任务是短暂的,并且类型为即发即弃)。
  • 主线程执行大量计算。最好的解决方案是对主线程性能的影响最小。
  • 还有一个线程的行为与此相同(持续时间相同),负责侦听来自所有客户端的数据。我打算应用与此操作相同的操作。

1 个答案:

答案 0 :(得分:0)

  

但是正如我所说,该操作应该持续整个应用程序

不,不是。该方法几乎立即返回。这就是异步方法的意思。工作完成时,它不会阻止呼叫者。

创建一个仅用于调用异步方法的新线程,就像雇用某人来您家为您的邮箱中放一封信一样。这比您自己完成更多的工作,因为将信发送到目的地的实际行为实际上并不能阻止您仅在开始工作时就进行一些琐碎的工作。