发表日期:2017-12-25 17:45:01文章编辑:025app.com 标签:公司新闻
对于IO密集型的应用(比如数据库访问,磁盘访问,网络访问)来讲,是不需要分配一个线程的(不怎么准确,但可以这么理解),那么使用一个后台线程运行这些操作来实现异步是低效的。而实际上我们的应用中充斥着大量的IO密集型操作(除了那些做游戏应用计算密集型)。经过测试,actualRead的长度可能会比BUFFER_LENGTH 小,但这并不代表网络传输已经结束,比如我采用异步方式下载网页的时候,我定义了1024的Buffer字节数组,但每次异步获取的字节长度都不足1024字节,在这种情况下不能关闭网络流的。线程间操作无效: 从不是创建控件“txtContent”的线程访问它。一般我们可以将我们的应用分为计算密集型,比如进行图像处理,解方程等,另一种就是IO密集型,比如访问数据库,访问磁盘等。
分清楚这两种了后我们再往下看。
计算密集型的代码是大量占用CPU时间,所以你用ThreadPool.QueueUserWorkItem也好,用BeginInvoke也好,都是分配一个线程来运算,无所谓(ThreadPool更佳)
IO密集型计算,我们大部分时间是在等待IO操作的,CPU并没有花多少时间来运算。所以我们不需要分配一个线程来单独进行IO,我们只需要使用异步发起IO操作,然后CPU自己干自己的事儿,当IO完成后,会回调。这样的效率就会更高。BeginInvoke不会创建线程,你从哪里看到的?
BeginInvoke是将操作放到另外一个线程上执行。这个线程来自线程池。
我的意思是说,对于IO操作不要将其放到另外一个线程上,这是浪费。
关于BeginInvoke是否创建线程要怎么看。
BeginInvoke调用时,CLR会将任务放到线程池的线程上执行,不是调用方法的线程了。
你可以在BeginInvoke的方法中设置一个断点,然后打开VS的线程窗口,你就可以发现该线程不是发起操作的线程。
另外,你从MSDN里引用的那个对BeginInvoke的解释是对委托的BeginInvoke的解释:
Action download = () => Download();
download.BeginInvoke();
它会使用线程池上的一个线程执行
这个是跟IO操作的BeginXXX不一样的。这是由操作系统实现的。
我们打个比方,我们去数据库查询一堆数据,那么你发起这个请求后,查询请求发送到数据库服务器,这个时候你自己的机器是不需要关心查询的执行是不?那我们只要数据库查询完毕,然后结果返回时有个机制告诉我们查询完了,你来处理吧。这就是IO异步。这样我们在查询数据库期间我们的线程不会阻塞(等结果),那么这个线程就可以去干其他事儿了,这样就能创建更少的线程,干更多的事儿。更少的线程线程上下文切换的几率就更小,消耗的资源也更少。
使用异步IO就是,我们发起一个异步IO请求,然后我们的线程就立马返回了,当请求有了结果,操作系统再从线程池里弄一线程处理后续流程。对于FileStream.BeginRead()会不会创建新的线程还是不确定,但是经过查找资料后得知,Net ThreadPool类中的线程分为Worker Thread和I/O Thread。而Worker Thread可以看成.Net通过Thread类预先创建的一组线程。.Net及ThreadPool类中提供的方法,如QueueUserWorkItem, Timer, delegate回调等使用的都是Worker Thread。而.Net中对I/O操作的封装,如FileStream, NetworkStream等则是使用的IO Thread。IO Thread是对I/O专门提供的,效率更高些!