在使用HttpClient做客户端调用一个API时 模拟并…

2018-06-24 00:00:15来源:未知 阅读 ()

新老客户大回馈,云服务器低至5折

平时还是比较喜欢看书的。。但有时候遇到问题还是经常感到脑袋一蒙。。智商果然是硬伤。。

同事发现了个问题,代码如下:

    class Program
    {
        static void Main(string[] args)
        {
            HttpClientClass c = new HttpClientClass();
            while (true)
            {
                Task.Factory.StartNew(() =>
                {
                    Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "开始请求:" + DateTime.Now);
                    c.BeginGetMethod();
                }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
                System.Threading.Thread.Sleep(10 * 1);
            }
        }
    }
    public class HttpClientClass
    {
        private static readonly HttpClient c;
        static HttpClientClass()
        {
            c = new HttpClient();
            c.Timeout = TimeSpan.FromSeconds(15);
        }
        public void BeginGetMethod()
        {
            try
            {
                var r = c.GetAsync("https://www.cnblogs.com/").Result;
                if (r.IsSuccessStatusCode)
                    Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "ok");
                else
                    Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "bad request");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.GetType().FullName);
            }
        }

在使用HttpClient的GetAsync请求后阻塞查询.Result“死锁了”,我们知道GetAsync内部也是一个后台线程在执行,直到获取到结果时会调用Task中的SetResult方法,然后通过.Result就能回去结果了。。

如果此处有问题,那我们假如做网站开发时,并发请求来了岂不是废掉了?!!

当然不是这样。。实际上线程池中处理任务时是存在任务队列的(不提看源码的事。。看完就忘。。)此处大概意思就是:主线程创建线程任务时,任务优先级高于后台线程创建的线程。这里的while不停的创建后台任务就导致了GetAsync方法中的后台任务一直在等啊等。。所以就发生了所谓的"死锁"。。其实是根本就没机会执行。。(没涉及到线程上下文切换,所以谈到这也能发生死锁时脑袋一蒙。。)

所以可以这么调用:

            Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    Task.Factory.StartNew(() =>
                    {
                        Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "开始请求:" + DateTime.Now);
                        c.BeginGetMethod();
                    }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
                    System.Threading.Thread.Sleep(10 * 1);
                }
            });

 

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:C#连接数据库MD5数据库加密

下一篇:.Net Core使用Socket与树莓派进行通信