• 你可能写了个假异步,并不能提高请求线程池的吞吐量


    不知道用什么词形容,就叫它假异步吧。

    写异步方法,async 和 await 要一路写到底,否则就是假异步,并不能提高请求线程池的吞吐量。

    真正的异步,我的理解是这样的:比如调用一个查询接口,在当前线程,把SQL扔给数据库,当前线程释放,去干别的事情,数据库查询完了,通知我,我再在另一个线程里(也可能是刚才释放的那个线程,也可能不是)拿查询结果,返回给客户端,数据库查询比较耗时,数据库查询的时候,对线程是0占用。
     
    HttpUtil.HttpGet方法:
    /// <summary>
    /// HttpGet
    /// </summary>
    /// <param name="url">url路径名称</param>
    /// <param name="cookie">cookie</param>
    public static string HttpGet(string url, CookieContainer cookie = null, WebHeaderCollection headers = null)
    {
        try
        {
            // 设置参数
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
            request.CookieContainer = cookie;
            request.Method = "GET";
            request.ContentType = "text/plain;charset=utf-8";
    
            if (headers != null)
            {
                foreach (string key in headers.Keys)
                {
                    request.Headers.Add(key, headers[key]);
                }
            }
    
            //发送请求并获取相应回应数据
            HttpWebResponse response = request.GetResponse() as HttpWebResponse;
            //直到request.GetResponse()程序才开始向目标网页发送Post请求
            Stream instream = response.GetResponseStream();
            StreamReader sr = new StreamReader(instream, Encoding.UTF8);
            //返回结果网页(html)代码
            string content = sr.ReadToEnd();
            instream.Close();
            return content;
        }
        catch (Exception ex)
        {
            LogUtil.Error(ex);
            return string.Empty;
        }
    }
    View Code

    HttpUtil.HttpGetAsync方法:

    /// <summary>
    /// HttpGetAsync
    /// </summary>
    /// <param name="url">url路径名称</param>
    /// <param name="cookie">cookie</param>
    public static async Task<string> HttpGetAsync(string url, CookieContainer cookie = null, WebHeaderCollection headers = null)
    {
        try
        {
            // 设置参数
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
            request.CookieContainer = cookie;
            request.Method = "GET";
            request.ContentType = "text/plain;charset=utf-8";
    
            if (headers != null)
            {
                foreach (string key in headers.Keys)
                {
                    request.Headers.Add(key, headers[key]);
                }
            }
    
            //发送请求并获取相应回应数据
            HttpWebResponse response = await request.GetResponseAsync() as HttpWebResponse;
            //直到request.GetResponse()程序才开始向目标网页发送Post请求
            Stream instream = response.GetResponseStream();
            StreamReader sr = new StreamReader(instream, Encoding.UTF8);
            //返回结果网页(html)代码
            string content = sr.ReadToEnd();
            instream.Close();
            return content;
        }
        catch (Exception ex)
        {
            LogUtil.Error(ex);
            return string.Empty;
        }
    }
    View Code

    测试代码:

    /// <summary>
    /// 测试1
    /// </summary>
    private async void button1_Click(object sender, EventArgs e)
    {
        //task是自己写的独立线程池,为了防止测试过程对CLR线程池和异步线程池造成干扰
        _task.Run(() =>
        {
            Thread.Sleep(200);
    
            int workerThreads1, completionPortThreads1, workerThreads2, completionPortThreads2;
            ThreadPool.GetMaxThreads(out workerThreads1, out completionPortThreads1);
            ThreadPool.GetAvailableThreads(out workerThreads2, out completionPortThreads2);
            Log("假异步 已使用辅助线程:" + (workerThreads1 - workerThreads2) + ", 已使用异步线程:" + (completionPortThreads1 - completionPortThreads2));
        });
    
        string str = await GetDataAsync();
    }
    
    /// <summary>
    /// 测试2 
    /// </summary>
    private async void button2_Click(object sender, EventArgs e)
    {
        //task是自己写的独立线程池,为了防止测试过程对CLR线程池和异步线程池造成干扰
        _task.Run(() =>
        {
            Thread.Sleep(200);
    
            int workerThreads1, completionPortThreads1, workerThreads2, completionPortThreads2;
            ThreadPool.GetMaxThreads(out workerThreads1, out completionPortThreads1);
            ThreadPool.GetAvailableThreads(out workerThreads2, out completionPortThreads2);
            Log("真异步 已使用辅助线程:" + (workerThreads1 - workerThreads2) + ", 已使用异步线程:" + (completionPortThreads1 - completionPortThreads2));
        });
    
        string str = await GetDataAsync2();
    }
    
    /// <summary>
    /// 假异步
    /// </summary>
    private async Task<string> GetDataAsync()
    {
        return await Task.Run<string>(() =>
        {
            //接口耗时大约1秒
            return HttpUtil.HttpGet("http://localhost:8500/api/test/TestGet?val=1", null, null);
        });
    }
    
    /// <summary>
    /// 真异步
    /// </summary>
    /// <returns></returns>
    private async Task<string> GetDataAsync2()
    {
        //接口耗时大约1秒
        return await HttpUtil.HttpGetAsync("http://localhost:8500/api/test/TestGet?val=1", null, null);
    }
    View Code

    测试截图:

    我想知道 WebRequest 类的 GetResponseAsync 方法是怎么实现的,反正使用.NET提供的类,我是无法实现这样的方法。

    这篇随笔如果有错误,请指正,我只是抛砖引玉,提出疑问或者说假设。

    async await 要一路写到底啊,重构压力真大。

    如果在异步方法中调用同步方法,又不想占用CLR线程池的线程,可以把耗时操作放到自己写的独立线程池中,例如:

    /// <summary>
    /// 测试GET请求
    /// </summary>
    /// <param name="val">测试参数</param>
    [HttpGet]
    [Route("TestGet")]
    [SwaggerResponse(HttpStatusCode.OK, "返回JSON", typeof(JsonListResult<TestGetResult>))]
    public async Task<HttpResponseMessage> TestGetAsync(string val)
    {
        var task = TaskHelper.RequestTask.Run(() => //使用自己写的独立线程池
        {
            List<TestGetResult> list = new List<TestGetResult>();
    
            Thread.Sleep(5000); //模拟耗时
    
            for (int i = 1; i <= 10; i++)
            {
                TestGetResult item = new TestGetResult();
                item.testValue1 = i.ToString();
                item.testValue2 = i;
                item.testValue3 = "这是传入参数:" + val;
                list.Add(item);
            }
    
            var jsonResult = new JsonListResult<TestGetResult>(list, list.Count);
    
            return ApiHelper.ToJson(jsonResult);
        });
    
        return await task;
    }
    View Code
  • 相关阅读:
    Nginx教程(三) Nginx日志管理
    Nginx教程(二) Nginx虚拟主机配置
    官方解析Cookies和Session的区别
    J2EE十三个技术规范
    J2EE十三个规范小结
    tomcat -web.xml里的内容
    tcp协议和udp协议的使用场景
    IntelliJ IDEA创建maven web项目(IDEA新手适用)
    Maven安装与配置
    X86、X64和X86_64区别
  • 原文地址:https://www.cnblogs.com/s0611163/p/13415212.html
Copyright © 2020-2023  润新知