\t\t线程池中执行的状态 和 定时器
来源:互联网 发布:投资组合分析软件 编辑:程序博客网 时间:2024/04/28 04:03
线程池中执行的函数
ThreadPool.QueueUserWorkItem 方法运行我们在系统线程池上启动一个函数,它的声明如下:
public static bool QueueUserWorkItem (WaitCallback callBack, object state)
第一个参数指明我们将在池中执行的函数,它的声明必须与WaitCallback代理(delegate)互相匹配:public delegate void WaitCallback (object state);
State 参数允许任何类型的信息传递到该方法中,它在调用QueueUserWorkItem时传入。
让我们结合这些新概念,看看“硬件商店”的另一个实现。
using System;
using System.Threading;
namespace ThreadPoolTest
{
class MainApp
{
static void Main()
{
WaitCallback callBack;
callBack = new WaitCallback(PooledFunc);
ThreadPool.QueueUserWorkItem(callBack,
"Is there any screw left?");
ThreadPool.QueueUserWorkItem(callBack,
"How much is a 40W bulb?");
ThreadPool.QueueUserWorkItem(callBack,
"Decrease stock of monkey wrench");
Console.ReadLine();
}
static void PooledFunc(object state)
{
Console.WriteLine("Processing request '{0}'", (string)state);
// Simulation of processing time
Thread.Sleep(2000);
Console.WriteLine("Request processed");
}
}
}
为了简化例子,我们在Main 类中创建一个静态方法用于处理请求。由于代理的灵活性,我们可以指定任何实例方法去处理请求,只要这些方法的声明与代理相同。在这里范例中,通过调用Thread.Sleep,实现延迟两秒以模拟处理时间。
你如果编译和执行这个范例,将会看到下面的输出:
Processing request 'Is there any screw left?'
Processing request 'How much is a 40W bulb?'
Processing request 'Decrease stock of monkey wrench'
Request processed
Request processed
Request processed
注意,所有的请求都被不同的线程并行处理了。
我们可以通过在两个方法中加入如下的代码,以此看到更多的信息。
// Main method
Console.WriteLine("Main thread. Is pool thread: {0}, Hash: {1}",
Thread.CurrentThread.IsThreadPoolThread,
Thread.CurrentThread.GetHashCode());
// Pool method
Console.WriteLine("Processing request '{0}'." +
" Is pool thread: {1}, Hash: {2}",
(string)state, Thread.CurrentThread.IsThreadPoolThread,
Thread.CurrentThread.GetHashCode());
我们增加了一个Thread.CurrentThread.IsThreadPoolThread的调用。如果目标线程属于线程池,这个属性将返回True。另外,我们还显示了用GetHashCode 方法从当前线程返回的结果。它是唯一标识当前执行线程的值。现在看一看这个输出结果:
Main thread. Is pool thread: False, Hash: 2
Processing request 'Is there any screw left?'. Is pool thread: True, Hash: 4
Processing request 'How much is a 40W bulb?'. Is pool thread: True, Hash: 8
Processing request 'Decrease stock of monkey wrench '. Is pool thread: True, Hash: 9
Request processed
Request processed
Request processed
你可以看到所有的请求都被系统线程池中的不同线程执行。再次运行这个例子,注意系统CPU的利用率,如果你没有任何其它应用程序在后台运行的话,它几乎是0%。因为系统唯一正在做的是每执行2秒后就挂起的处理。
我们来修改一下这个应用,这次我们不挂起处理请求的线程,相反我们会一直让系统忙,为了做到这点,我们用Environment.TickCount. 构建一个每隔两秒就对请求执行一次的循环。
int ticks = Environment.TickCount;
while(Environment.TickCount - ticks < 2000);
现在打开任务管理器,看一看CPU的使用率,你将看到应用程序占有了CPU的100%的使用率。再看一下我们程序的输出结果:
Processing request 'Is there any screw left?'. Is pool thread: True, Hash: 7
Processing request 'How much is a 40W bulb?'. Is pool thread: True, Hash: 8
Request processed
Processing request 'Decrease stock of monkey wrench '. Is pool thread: True, Hash: 7
Request processed
Request processed
注意第三个请求是在第一个请求处理结束之后执行的,而且线程的号码仍然用原来的7,这个原因是线程池检测到CPU的使用率已经达到100%,一直等待某个线程空闲。它并不会重新创建一个新的线程,这样就会减少线程间的上下文切换开销,以使总体性能更佳。
使用定时器
假如你曾经开发过Microsoft Win32的应用程序,你知道SetTimer函数是API之一,通过这个函数可以指定的一个窗口接收到来自系统时间周期的WM_TIMER消息。用这个方法遇到的第一个问题是你需要一个窗口去接收消息,所以你不能用在控制台应用程序中。另外,基于消息的实现并不是非常精确,假如你的应用程序正在处理其它消息,情况有可能更糟糕。
相对基于Win32的定时器来说, .NET 中一个很重要的改进就是创建不同的线程,该线程阻塞指定的时间,然后通知一个回调函数。这里的定时器不需要Microsoft的消息系统,所以这样就更精确,而且还能用于控制台应用程序中。以下代码显示了这个技术的一种实现:
class MainApp
{
static void Main()
{
MyTimer myTimer = new MyTimer(2000);
Console.ReadLine();
}
}
class MyTimer
{
int m_period;
public MyTimer(int period)
{
Thread thread;
m_period = period;
thread = new Thread(new ThreadStart(TimerThread));
thread.Start();
}
void TimerThread()
{
Thread.Sleep(m_period);
OnTimer();
}
void OnTimer()
{
Console.WriteLine("OnTimer");
}
}
这个代码一般用于Wn32应用中。每个定时器创建独立的线程,并且等待指定的时间,然后呼叫回调函数。犹如你看到的那样,这个实现的成本会非常高。如果你的应用程序使用了多个定时器,相对的线程数量也会随着使用定时器的数量而增长。
现在我们有.NET 提供的线程池,我们可以从池中改变请求的等待函数,这样就十分有效,而且会提升系统的性能。我们会遇到两个问题:
n 假如线程池已满(所有的线程都在运行中),那么这个请求排到队列中等待,而且定时器不在精确。
n 假如创建了多个定时器,线程池会因为等待它们时间片失效而非常忙。
为了避免这些问题,.NET框架的线程池提供了独立于时间的请求。用了这个函数,我们可以不用任何线程就可以拥有成千上万个定时器,一旦时间片失效,这时,线程池将会处理这些请求。
这些特色出现在两个不同的类中:
System.Threading.Timer
定时器的简单版本,它运行开发人员向线程池中的定期执行的程序指定一个代理(delegate).
System.Timers.Timer
System.Threading.Timer的组件版本,允许开发人员把它拖放到一个窗口表单(form)中,可以把一个事件作为执行的函数。
这非常有助于理解上述两个类与另外一个称为System.Windows.Forms.Timer.的类。这个类只是封装了Win32中消息机制的计数器,如果你不准备开发多线程应用,那么就可以用这个类。
在下面的例子中,我们将用System.Threading.Timer 类,定时器的最简单实现,我们只需要如下定义的构造方法
public Timer(TimerCallback callback,
object state,
int dueTime,
int period);
对于第一个参数(callback),我们可以指定定时执行的函数;第二个参数是传递给函数的通用对象;第三个参数是计时器开始执行前的延时;最后一个参数period,是两个执行之间的毫秒数。
下面的例子创建了两个定时器,timer1和timer2:
class MainApp
{
static void Main()
{
Timer timer1 = new Timer(new TimerCallback(OnTimer), 1, 0, 2000);
Timer timer2 = new Timer(new TimerCallback(OnTimer), 2, 0, 3000);
Console.ReadLine();
}
static void OnTimer(object obj)
{
Console.WriteLine("Timer: {0} Thread: {1} Is pool thread: {2}",
(int)obj,
Thread.CurrentThread.GetHashCode(),
Thread.CurrentThread.IsThreadPoolThread);
}
}
输出:
Timer: 1 Thread: 2 Is pool thread: True
Timer: 2 Thread: 2 Is pool thread: True
Timer: 1 Thread: 2 Is pool thread: True
Timer: 2 Thread: 2 Is pool thread: True
Timer: 1 Thread: 2 Is pool thread: True
Timer: 1 Thread: 2 Is pool thread: True
Timer: 2 Thread: 2 Is pool thread: True
犹如你看到的那样,两个定时器中的所有函数调用都在同一个线程中执行(ID = 2),应用程序使用的资源最小化了。
- \t\t线程池中执行的状态 和 定时器
- Java中 <? super T>,<? extends T>,和<T>的区别
- Java中 <? super T>,<? extends T>,和<T>的区别
- Java中 <? super T>,<? extends T>,和<T>的区别
- \t\t.NET 线程池
- std::stack<T>和std::queue<T>在执行频率比较高的程序中,效率太低
- C#中List<T> 和 IList<T> 的比较
- C#中IComparable<T>和IComparer<T>接口的使用
- C#中 Action<T>和Func<T>的用法
- Java中<? extends T>和<? super T>的理解
- Java中<? extends T>和<? super T>的理解
- Java中<? extends T>和<? super T>的理解
- \t\t同步 异步线程池
- \t\t监视线程池 死锁
- 实现一个应用层的定时器T^T
- 子线程中执行定时器
- T-SQL的执行顺序
- Java中T和?的区别
- \t\t让老板在第一时间想到你!
- \t\t网络出现“音频毒品”,听了使人上瘾 音频毒品试听地址
- \t\t用C#编写ActiveX控件 自定义html控件 ActiveX 控件注册 标记Activex控件为脚本安全
- \t\t.NET 线程池
- stfp开启
- \t\t线程池中执行的状态 和 定时器
- \t\t同步 异步线程池
- \t\t监视线程池 死锁
- \t\t多线程有关安全性
- \t\t用js控制页面图片等比缩放 css图片等比缩放 比例缩放显示 js 页面 缩放图片 js缩放图片 图片按比例缩放
- \t\tAsp.net Forms验证 角色验证 用户授权
- \t\t劳动试用
- \t\t孕妇的骨盆测量及检查
- \t\t商业智能,又称商务智能,英文为Business Intelligence,简写为BI 搭建BI系统