打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
《CLR via C#》读书笔记

《CLR via C#》读书笔记-.NET多线程(六)

作者:zlbcdn

parallel处理
当存在以下情况:
1、需处理多个独立方法
2、各方法之间不存在共享资源的情况
3、各方法可以使用相同的委托
就可以使用Parallel类的相关方法进行处理
以下是官网上的一个例子,

using System.Threading.Tasks;   class Test{    static int N = 1000;    static void TestMethod()    {        // Using a named method.        Parallel.For(0, N, Method2);        // Using an anonymous method.        Parallel.For(0, N, delegate(int i)        {            // Do Work.        });    //Using ForEach    Parallel.ForEach(collection,item=>DoWork(item));        // Using a lambda expression.        Parallel.For(0, N, i =>        {            // Do Work.        });    }    static void Method2(int i)    {        // Do work.    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

个人认为在这功能有点语法糖感觉。原因有两个:
原因一:从这个语法的本身而言,其使用多线程处理操作,本身就会消耗资源,因此parallel类更适合处理较复杂、耗时较长的操作。范围缩小了!
原因二:即使处理较复杂、耗时较长的任务,在业务上也大多是使用同一数据库事务,这样就能保证要么全成功要么全失败。而使用parallel类出现部分失败时,对于业务而言就比较困难了。
综上,个人认为对于parallel适应的范围不是很大。
定时器
定时器需要好好的写写!我的业务程序有一需求,就是比较频繁的定时查找数据,并将数据打印出来!之前使用WinForm界面上的timer,结果悲剧,当处理大量数据时,会存在两个问题:1、界面卡死;2、相同的内容会打印多遍(一般会打印2遍)。这两个问题那段时间经常被业务部门投诉!后来使用了多线程的定时器,解决了这个问题。
System.Threading.Timer类的构造函数如下所示:

public Timer(TimerCallback callback,object state,int dueTime,int period)
  • 1

Timer构造器中四个参数的的定义分别如下:
callback的委托定义如下

public delegate void TimerCallback(    object state)
  • 1
  • 2
  • 3

state为callback的参数值,若为空,可为null;
dueTime为从准备到执行的时间
period为时间每次操作的时间间隔
因此timer的一般使用方式如下:

//以下代码为伪码private system.threading.timer doSomeThingTimer=null;//开始执行定时操作的button按钮public void button_click(e){    doSomeThingTimer = new system.threading.timer(doSomeWork,null,5000,timeout.infinite);}//具体的业务逻辑方法private void doSomeWork(object status){    //业务逻辑代码    //这儿一定要使用change方法,改变定时操作    doSomeThingTimer.change(8000,timeout.infinite);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

以上就是使用timer的具体方法,其中doSomeWork方法中使用了change方法。原因如下:若不使用change方法,而是在timer中定义好操作每次的执行间隔,则会出现以下情况。若操作的时间很长,超过了每次的执行间隔,则线程池就会调用额外的线程去执行操作,相当于有两个线程分别去执行doSomeWork。因此,为了避免这种情况的发生,需要在操作中使用change方法。
Timer小结
1、system.threading.timer类是使用线程池线程,其内部使用了Threadpool.queueUserWorkItem()方法。这也是为何timer的委托与queueUserWorkItem的委托一致的原因。
2、在线程池内部,线程池为所有的system.threading.timer共同使用一个线程。若一个不够用,则会额外再开立新的线程
3、system.windows.forms.timer中也有一个定时器,但该定时器属于UI线程,实UI线程有一消息泵,定时启动该定时器。这个定时器适合用于非常简单、耗时短、更新界面相关的操作。用于后台的或耗时的操作,请不要使用
4、system.windows.threading.dispatcherTimer类是system.windows.forms.timer在wpf和silverlight的等价物
5、system.timers.timer类。这个类很有意思,它是一个控件,当定时触发时,它会调用CLR的线程池线程进行操作。按理说它是正合适,但是它也有历史,它是不应该存在的。因为在微软大规模整理线程和定时器相关的方法之前,就把它留在了FCL中,因此由于历史原因,它也就没被删除。但平时尽量不要使用它。
线程池相关
当前线程池的上限是1000,一般情况下不要更改线程池的任何限定。


当使用threadpool.queueuserworkitem()及system.threding.timer创建的工作项会存放到上图中的全局队列中。然后线程池中的线程(也就是图中的工作者线程),会按照FIFO(先入先出,队列)的原则从全局队列中获取工作项,以进行完成。在这个过程中全局队列有一个同步锁,防止多个线程抢夺一个工作项。当工作者线程选取工作项后,全局队列就会将该工作项在列表中删除。
若此时,创建了一个task,则线程池会将task工作项放置在上图中的本地队列中。从而工作者线程就会优先到本地队列中获取工作项。选取方式与全局队列有区别,是后入先出的原则(即栈)获取工作项。若本地队列中已经没了工作项,则线程会到其他本地队列中“偷取”工作项进行处理。若所有的本地队列中的工作项都处理完了,则工作者线程就到全局队列中获取工作项。若全局队列中的工作项都处理完了,则工作者线程就会睡眠,然后一定时间段后自然醒来,若发现还没有事情做,就自杀掉。
若是一个外部的非工作者线程(例如,window线程),则不管是Threadpool还是timer还是task,CLR都将其放入全局队列中,非工作者线程会从全局队列中获取工作项以进行工作。
伪共享
我的系统是64位的操作系统,这也就意味着,系统可以一次性读取64byte的数据,因此创建2个int32的数据时,很有肯能两个int32变量存储在一个缓存线里。因此有两个线程对两个变量进行多次操作的时候,就会因读取相同的内容而进行资源的争夺,因此会造成性能的降低。因此为了避免这种“伪共享”的情况导致的性能下降,可以采用一些attribute,使两个字段分配到两个缓存线中,这样就会使性能提升。
26章小结
主要就是讲述了task。
待解决问题
整理attribute
26章完

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Linux下的定时器的实现
python线程定时器Timer(32)
python定时器
51单片机IO口模拟串口通讯C源程
51单片机1602LCD显示数字频率计
.NET基础知识-进程与线程
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服