【编写高质量代码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占用。

时间: 2024-12-09 17:04:29

【编写高质量代码C#】建议71:区分异步和多线程应用场景的相关文章

编写高质量代码改善C#程序的157个建议——建议87:区分WPF和WinForm的线程模型

建议87:区分WPF和WinForm的线程模型 WPF和WinForm窗体应用程序都有一个要求,那就是UI元素(如Button.TextBox等)必须由创建它的那个线程进行更新.WinForm在这方面的限制并不是很严格,所以像下面这样的代码,在WinForm中大部分情况下还能运行(本建议后面会详细解释为什么会出现这种现象): private void buttonStartAsync_Click(object sender, EventArgs e) { Task t = new Task(()

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

建议103:区分组合和继承的应用场合 继承所带来的多态性虽然是面向对象的一个重要特性,但这种特性不能在所有的场合中滥用.继承应该被当做设计架构的有用补充,而不是全部. 组合不能用于多态,但组合使用的频率却要远远高于继承. 继承UML图如下: 对应的代码如下: abstract class Stream { //省略 } class FileStream:Stream { //省略 } class MemoryStream : Stream { //省略 } 组合UML图如下: 对应代码如下: c

编写高质量代码改善C#程序的157个建议——建议102:区分接口和抽象类的应用场合

建议102:区分接口和抽象类的应用场合 接口和抽象类有一些显而易见的区别: 接口支持多继承,抽象类则不能. 接口可以包含方法.属性.索引器.事件的签名,但不能有实现,抽象类则可以. 接口在增加新方法后,所有的继承者都必须重构,否则编译不通过,而抽象类则不需要. 这些区别导致两者的应用场景不同: 如果对象存在多个功能相近且关系紧密的版本,则使用抽象类. 如果关系不紧密,但若干功能拥有共同的声明,则使用接口. 抽象类适合于提供丰富功能的场合,接口则更倾向于提供单一的一组功能. 从某种角度来看,抽象类

编写高质量代码改善C#程序的157个建议[优先考虑泛型、避免在泛型中声明静态成员、为泛型参数设定约束]

前言 泛型并不是C#语言一开始就带有的特性,而是在FCL2.0之后实现的新功能.基于泛型,我们得以将类型参数化,以便更大范围地进行代码复用.同时,它减少了泛型类及泛型方法中的转型,确保了类型安全.委托本身是一种引用类型,它保存的也是托管堆中对象的引用,只不过这个引用比较特殊,它是对方法的引用.事件本身也是委托,它是委托组,C#中提供了关键字event来对事件进行特别区分.一旦我们开始编写稍微复杂的C#代码,就肯定离不开泛型.委托和事件.本章将针对这三个方面进行说明. 这里也有一篇之前我对泛型的简

编写高质量代码改善C#程序的157个建议——建议29:区别LINQ查询中的IEnumerable&lt;T&gt;和IQueryable&lt;T&gt;

建议29:区别LINQ查询中的IEnumerable<T>和IQueryable<T> LINQ查询一共提供了两类扩展方法,在System.Linq命名空间下,有两个静态类:Enumerable类,它针对继承了IEnumerable<T>接口的集合进行扩展:Queryable类,它针对继承了IQueryable<T>接口的集合类进行扩扎.接口IQueryable<T>也是继承了IEnumerable<T>接口的,所以,致使两个接口的方

编写高质量代码改善C#程序的157个建议[为泛型指定初始值、使用委托声明、使用Lambda替代方法和匿名方法]

前言 泛型并不是C#语言一开始就带有的特性,而是在FCL2.0之后实现的新功能.基于泛型,我们得以将类型参数化,以便更大范围地进行代码复用.同时,它减少了泛型类及泛型方法中的转型,确保了类型安全.委托本身是一种引用类型,它保存的也是托管堆中对象的引用,只不过这个引用比较特殊,它是对方法的引用.事件本身也是委托,它是委托组,C#中提供了关键字event来对事件进行特别区分.一旦我们开始编写稍微复杂的C#代码,就肯定离不开泛型.委托和事件.本章将针对这三个方面进行说明. 本文已更新至http://w

编写高质量代码改善python程序91个建议学习01

编写高质量代码改善python程序91个建议学习 第一章 建议1:理解pythonic的相关概念 狭隘的理解:它是高级动态的脚本编程语言,拥有很多强大的库,是解释从上往下执行的 特点: 美胜丑,显胜隐,简胜杂,杂胜乱,平胜陡,疏胜密 python定义 #python排序 def quicksort(arr): less=[];greater=[] if len(arr)<=1: return arr pivot=arr.pop() for x in arr: if x<=pivot: less

编写高质量代码,改善C++程序的150个建议:指针、初始化和运算符

建议0:不要让main函数返回void 首先C++ 标准中从没有出现过void main(){}这样的函数定义. 标准的主函数定义有两种: int main() int main(int argc,char * argv[]) 在main函数中,return 语句的作用在于离开main函数(析构掉所有具有动态生存时间的对象),并将其返回值作为参数来调用exit函数.如果函数执行到结尾儿没有遇到return 语句,其效果就等于执行了return 0. 建议1:区分0 的四种面孔 1)整形0.作为一

编写高质量代码改善C#程序的157个建议——建议78:应避免线程数量过多

建议78:应避免线程数量过多 在多数情况下,创建过多的线程意味着应用程序的架构设计可能存在着缺陷.经常有人会问,一个应用程序中到底含有多少线程才是合理的.现在我们找一台PC机,打开Windows的任务管理器,看看操作系统中正在运行的程序有多少个线程. 在笔者当前的PC机上,线程数最多的一个应用程序是某款杀毒软件,它一共拥有116个线程数:其次是Windows自身的System进程,当前共有104个线程:第三多的进程是Sqlservr.exe,锐减到了35个线程:剩下还有63个进程,估计它们平均约

每周一书-编写高质量代码:改善C程序代码的125个建议

首先说明,本周活动有效时间为2016年8月28日到2016年9月4日.本周为大家送出的书是由机械工业出版社出版,马伟编著的<编写高质量代码:改善C程序代码的125个建议>. 编辑推荐 10余年开发经验的资深C语言专家全面从C语法和C11标准两大方面深入探讨编写高质量C代码的技巧.禁忌和实践 C语言因为既具有高级语言特性,又具有汇编语言特性,所以它是近二十几年来使用较为广泛.生命力较强的编程语言.无论是操作系统.嵌入式系统.普通应用软件,还是移动智能设备开发,它都能够很好地胜任,是公认的强大的语