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)
Timer构造器中四个参数的的定义分别如下:
callback的委托定义如下
public delegate void TimerCallback(
object state
)
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章完