多次调用静态httpclient会挂起控制台应用程序

时间:2017-04-13 02:14:26

标签: c# asynchronous

我注意到当我使用HttpClient的单个静态实例时,我的代码挂起,并在几分钟后退出并出现错误 - 只是说其中一个任务被取消而没有给出特定的错误。

    static HttpClient _client = new HttpClient();
    static void Main(string[] args)
    {
        try
        {
            var t1 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt");
            t1.Wait();
            Console.WriteLine("complete");
            var t2 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt");
            t2.Wait();
            Console.WriteLine("complete");
            var t3 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt");
            t3.Wait();
            Console.WriteLine("complete");
            var t4 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt");
            t4.Wait();
            Console.WriteLine("complete");
            Console.ReadKey();

        }
        catch (System.Exception ex)
        {

        }

    }

当我切换到以下代码并创建HttpClient的单独实例时,问题就消失了。

    static void Main(string[] args)
    {
        try
        {
            HttpClient client1 = new HttpClient();
            var t1 = client1.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt");
            t1.Wait();
            Console.WriteLine("complete");
            HttpClient client2 = new HttpClient();
            var t2 = client2.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt");
            t2.Wait();
            Console.WriteLine("complete");
            HttpClient client3 = new HttpClient();
            var t3 = client3.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt");
            t3.Wait();
            Console.WriteLine("complete");
            HttpClient client4 = new HttpClient();
            var t4 = client4.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt");
            t4.Wait();
            Console.WriteLine("complete");
            Console.ReadKey();
        }
        catch (System.Exception ex)
        {

        }

    }

我想知道为什么会发生这种情况,如果有一种方法可以安全地使用静态HttpClient,就像我在第一个代码块中一样(不是必需的,只是出于好奇)

1 个答案:

答案 0 :(得分:1)

问题是,你使用" GetStreamAsync"方法。如果您使用一个实例将此方法称为多个,则" _client"打开相同的流多个并将此流复制到" t1"," t2",...您使用此打开的流创建死锁。你应该使用" GetStringAsync"或者你应该在" _client"之前关闭流" t1"打开" t2"等等。以下代码显示了如何执行此操作:

class Program
{
    private static HttpClient _client = new HttpClient();

    static void Main(string[] args)
    {
        try
        {
            using (var t1 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"))
            {
                t1.Wait();
                Console.WriteLine("complete");
            }

            using (var t2 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"))
            {
                t2.Wait();
                Console.WriteLine("complete");
            }

            using (var t3 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"))
            {
                t3.Wait();
                Console.WriteLine("complete");
            }

            using (var t4 = _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"))
            {
                t4.Wait();
                Console.WriteLine("complete");
            }

            Console.ReadKey();

        }
        catch (System.Exception ex)
        {

        }
    }

我添加了一个简单的使用,如果程序离开" t1"的使用块,则会自动调用" t1"的处理方法。

此外,我建议您使用" await"用异步代码干净利落地工作。问题是,你不能使用"等待"在你的代码中,是" Main"方法不能用于异步方法。但您可以通过创建一个新的异步void方法来处理这个问题,如下所示:

class Program
{
    private static HttpClient _client = new HttpClient();

    static void Main(string[] args)
    {

        GetStreamsAsync();
        Console.ReadKey();
    }

    static async void GetStreamsAsync()
    {
        try
        {
            using (var t1 = await _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"))
            {
                Console.WriteLine("complete");
            }

            using (var t2 = await _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"))
            {
                Console.WriteLine("complete");
            }

            using (var t3 = await _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"))
            {
                Console.WriteLine("complete");
            }

            using (var t4 = await _client.GetStreamAsync("http://www.w3.org/TR/PNG/iso_8859-1.txt"))
            {
                Console.WriteLine("complete");
            }
        }
        catch (System.Exception ex)
        {

        }
    }
}

你必须调用" Console.ReadKey" " Main"中的方法方法,因为" Main"方法在新的" async void GetSteamsAsync"之前完成。方法

更新(感谢Stuart的评论): 如果您使用其他应用程序模型,建议使用" ConfigureAwait"同样。使用" ConfigureAwait"是没有意义的。在控制台应用程序中,因为没有SynchronizationContext可以捕获并继续。