编写高质量代码C#建议71:区分异步和多线程应用场景

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了编写高质量代码C#建议71:区分异步和多线程应用场景相关的知识,希望对你有一定的参考价值。

1.在获取网页内容的时候,可能由于网络不好,获取时间会很长,这时候我们一般会使用新建一个线程去获取,这样在获取网页的这段时间中,主线程就不会阻滞了。

        private void btnGetPage_Click(object sender, EventArgs e)
        {
            Thread th = new Thread(() =>
            {
                //没有下面这一行会报线程无效的异常
                //设置是否捕获对错误线程的调用,调用时会访问应用程序空间的属性
                Control.CheckForIllegalCrossThreadCalls = false;
                var req = HttpWebRequest.Create("http://www.sina.com.cn");
                var resp = req.GetResponse();
                Stream stream = resp.GetResponseStream();
                using (StreamReader sr=new StreamReader(stream,Encoding.UTF8))
                {
                    textBox1.Text = sr.ReadToEnd();
                }
            });
            th.Start();
        }

上面的例子解决了主线程可能被阻滞的问题,但是新建的获取网页的线程一直在占用系统的资源,显然是不高效的。接下来,我们考虑用异步模式去实现。

2.异步模式获取网页内容

        private void btnGetPage2_Click(object sender, EventArgs e)
        {
            var req = (HttpWebRequest)HttpWebRequest.Create("http://www.sina.com.cn");
            //开始对Internet资源的异步请求
            req.BeginGetResponse(AsyncCallbackImpl, req);

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ar">异步操作的状态</param>
        public void AsyncCallbackImpl(IAsyncResult ar)
        {
            //获取异步请求
            WebRequest webreq = ar.AsyncState as WebRequest;
            
            var resp = webreq.EndGetResponse(ar);
            var stream2 = resp.GetResponseStream();
            using (StreamReader sr = new StreamReader(stream2))
            {
                var strdocument = sr.ReadToEnd();
                //调用方调用控件方法时是否必须调用Invoke方法,因为调用方线程在控件线程以外
                if (textBox2.InvokeRequired)
                {
                    //1. 委托使用
                    //del d=NewMethod;
                    //textBox2.Invoke(d,strdocument);

                    //2. 直接使用new Action()
                    textBox2.Invoke(new Action(() =>
                    {
                        textBox2.Text = strdocument;
                    }));
                }
                else
                {
                    textBox2.Text = strdocument;
                }

                if (textBox1.InvokeRequired)
                {
                    textBox1.Invoke(new Action(() => { 
                    
                    }));
                }
            }
        }

  采用异步模式,它使用线程池进行管理。这时候获取网页就不会占用任何CPU了,更高效!

3.多线程和和异步分别在怎样的应用场景中使用?

从上例子可以分析得到:

在计算密集型工作中应考虑使用多线程,避免线程阻滞;在I/O密集型工作中应考虑使用异步模式,减少CPU占用。

以上是关于编写高质量代码C#建议71:区分异步和多线程应用场景的主要内容,如果未能解决你的问题,请参考以下文章

编写高质量代码改善C#程序的157个建议——建议86:Parallel中的异常处理

编写高质量代码改善C#程序的157个建议——建议103:区分组合和继承的应用场合

编写高质量代码改善C#程序的157个建议——建议107:区分静态类和单例

编写高质量代码改善C#程序的157个建议——建议143:方法抽象级别应在同一层次

编写高质量代码改善C#程序的157个建议——建议137:委托和事件类型应添加上级后缀

编写高质量代码改善C#程序的157个建议——建议99:重写时不应使用子类参数