是否应始终等待任务?

时间:2016-10-03 21:27:09

标签: c# asynchronous tcp client-server task

我正在创建一个可以拥有多个客户端的异步服务器。与聊天客户端/服务器体系结构类似,所有客户端都会根据任何客户端的请求更新每个服务器状态更改。我发现了很多例子,并编写了一个简单的测试应用程序。我刚刚编写了客户端请求的处理,但遇到了我通常不会遇到的情况。这是我写的示例服务器:

class Server
{
    int _port;
    TcpListener _listener;
    IList<TcpClient> _clients = new List<TcpClient>();

    public Server(int port)
    {
        _port = port;
        _listener = new TcpListener(IPAddress.Any, _port);
    }

    public async Task StartListening()
    {
        _listener.Start();
        Console.WriteLine("The server is listening on port {0}...", _port);

        while (true)
        {
            try
            {
                var client = await _listener.AcceptTcpClientAsync();
                Console.WriteLine("We have a client!");
                _clients.Add(client);
                Process(client);

            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
    }

    private async Task Process(TcpClient client)
    {
        try
        {
            var stream = client.GetStream();
            var reader = new StreamReader(stream);
            var writer = new StreamWriter(stream) { AutoFlush = true };
            char[] buffer = new char[1024];
            while (true)
            {
                var request = await reader.ReadLineAsync();
                if (request != null)
                {
                    Console.WriteLine(request);
                }
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
            client.Close();
        }
    }

}

这是Program.cs:

class Program
{
    static void Main(string[] args)
    {
        var server = new Server(6029);
        server.StartListening().Wait();
    }
}

因为没有等待任务,我在进程调用上收到警告。我理解没有await调用的代码的行为,但我想知道我是否应该以不同的方式编码(ThreadPool等等),即使这给了我想要的行为。应该总是等待任务吗?

1 个答案:

答案 0 :(得分:0)

很难知道你在这里真正要求的是什么。您已经问过&#34;隐含的具体问题,我想知道我是否应该采用不同的编码方式&#34; ,以及广泛的,主要基于意见的问题&#34;是否应始终等待任务?&#34;

对于后者,唯一可以理解为正确的答案是&#34;没有。&#34;编程中几乎没有任何东西总是必须完成。

那就是说,你发布的代码肯定有缺陷。首先,你有一个永远无法完成的async Task方法。这是什么意思?你也可以声明它async void。该程序可以通过其他一些机制无限期地等待,例如无限长时间睡眠或阻塞Console.ReadLine()方法等。

更好的是,给程序一个优雅地关闭自己的方法。如果希望服务器停止侦听,请关闭侦听套接字。存储Task返回的所有Process()个对象,并在允许该过程完成之前等待它们,以确保您的服务器正常关闭连接而不是强行重置它们。

您发布的代码实际上并不具体,无法提供任何具体的建议方式。它看起来像初学者代码,主要用于演示一些基本概念,而不是做任何真实的事情。因此,它必然会受到与在所有情况下都能正常工作的代码不同的规则的约束。


在我看来,鉴于您的代码示例,我等待您创建的任务。您不一定需要使用await Process(...)(事实上,您可能不想,因为这会阻止您一次处理多个客户端),但您应该保留参考并最终等待。

但这是否意味着Task必须总是等待?不,这只是意味着在你的例子中,你没有表现出令人信服的理由。在大多数情况下,你应该。如果没有别的,它让你有机会观察可能发生的任何异常(说到哪个,你不应该抓住Exception ...只抓住你期望的那些例外,你知道如何处理它们) 。但在极少数情况下,如果没有其他原因,除了简单的实用性(或者更确切地说,试图观察的不切实际)之外,一旦它开始,你就不会注意你已经开始的任务是有道理的。任务)。


补充阅读:
How to safely call an async method in C# without await
warning this call is not awaited, execution of the current method continues
Where to stop using async /await keywords?