代码改变世界

Thread基础-计算限制的异步操作(CLR)

2011-11-28 23:41  木木子  阅读(661)  评论(0编辑  收藏  举报

本章笔记内容:

    • 闲话
    • CLR线程池基础;
    • 执行简单的计算限制操作;
    • 执行上下文;
    • 协作式取消;

闲话

该笔记记录的是Jiffrey Richter《CLR via C#》 3rd Edition的chapter 26 Compute-Bound Asynchronous Operations的前四节内容。

Jiffrey Richter《CLR via C#》3rd Edition下载地址:这里 或者 wowebook中找。

在这里你能过找到一些简单的执行异步操作的例子。

CLR线程池基础

所谓线程池,通俗地讲,就是一大堆线程的集合,可以给你的应用程序所使用。但是,线程池刚初始化时,是没有一个线程的。主要是因为,太多的线程会消耗内存资源和降低性能。当你的application需要进行异步计算,某些方法进入线程池队列,线程池创建第一个线程。由于创建线程有个performance hit,所以当线程池中德线程完成任务后,不会被destroy。相反地,返回给线程池等待下个调用,这样就没有产生performance hit了。

上述情况是只有一个线程或少量线程请求调用,当你的application产生大量请求时,线程池首先会试着用一个线程来完成。但当application请求适度大于线程的处理速度,这时另外的线程就创建了。因此,线程池是会创建尽可能少得线程来处理application的请求,保障了performance。

线程池把所有请求处理完后,也木有产生新的请求。在一个周期后,线程会自杀。这样就不会浪费内存资源。

所以,线程池会自我权衡,建立少量线程来减少损耗;建立更多的线程来提高效率。

线程池中的线程分为:worker thread 和I/O thread。

以下是使用线程池的方法(在threadPool class中定义):

Static Boolean QueueUserWorkItem(WaitCallback callBack);

Static Boolean QueueUserWorkItem(WaitCallback callBack, Object state);

Sysytem.Threading.WaitCallback委托类定义如下:

delegate void WaitCallback(Object state);

Coding一个:

static void Main(string[] args)
{
    Console.WriteLine("Main thread.");
    Thread.Sleep(1000);
    ThreadPool.QueueUserWorkItem(state =>
    {
        Console.WriteLine("Other thread");
        Thread.Sleep(1000);
    });
    Console.WriteLine("Main thread is doing other work");
    Thread.Sleep(1000);
    Console.WriteLine("Hit <Enter> to end this program...");
    Console.ReadKey();
}

 

Run 输出:

Main thread.
Main thread is doing other work
Other thread

也可能输出:

Main thread.
Main thread is doing other work
Other thread

执行上下文

每个线程都有一个执行上下文(Execution Contexts)。执行上下文包含security setting(compressed stack, Thread`s Principal property and Windows identity)、host setting(详细见System.Threading.)HostExecutionContextManager) 和 logical call context data(详细见System.Runtime.Remoting.Messaging.CallContext的方法——LogicalSetData和LogicalGetData)。

当前线程开启一个线程(helper thread)时,当前的执行上下文会自动流到helper thread,这样保障了security setting和host setting的一致性。执行上下文的复制到新线程是要性能损耗的。在System.Thread中有一个类叫ExecutionContext可以控制执行上下文的流动。

ExecutionContext类似于:

public sealed class ExecutionContext : IDisposable, ISerializable

{

[SecurityCritical]

public static AsyncFlowControl  SuppressFlow();

public static void RestoreFlow();

public static Boolean IsFlowSuppressed();
}

你能够使用ExecutionContext 控制执行上下文流动,从而提高应用程序的性能,在服务程序中能得到显著地提高,而在客户端程序不会很有效。当然,为了不让新的线程使用执行上下文中的数据时使用该类实现。

附上一个简单的例子:

CallContext.LogicalSetData("Name", "LiLin");
ThreadPool.QueueUserWorkItem(state => Console.WriteLine("My name is {0}", CallContext.LogicalGetData("Name")));
 
ExecutionContext.SuppressFlow();
ThreadPool.QueueUserWorkItem(state => Console.WriteLine("My name is {0}", CallContext.LogicalGetData("Name")));
 
ExecutionContext.RestoreFlow();
输出

My name is LiLin
My name is

 

协作式取消

MicroSoft .NET Framework为取消操作提供一标准模式,叫做协作式。换句话说,你可以明确规定你的操作可以被取消,这对于耗时的肌酸异步限制操作很有用。

实现协作式取消,会用到System.Threading.CancellationTokenSource这个类,这个类的定义类似于:

public sealed class CancellationTokenSource : IDisposable

{

public CancellationTokenSource ();

public void Dispose();

 

public Boolean IsCancellationRequested { get ; }

public CancellationToken Token { get ; }

 

public void Canel();

public void Cancel( Boolean throwOnFirstException);
}

CancellationTokenSource 是引用类型,而CancellationToken 是值类型,定义类似于:

public struct CancellationToken

{

public Boolean isCanllationRequested { get; }

public void ThrowIfCancellationRequested();

 

public WaitHandle WaitHandle { get; }

public static CancellationToken None { get; };

public Boolean CanBeCanceled { get ; }

 

public CancellationTokenRegistration Register( Action<Object> callback, Object state, Boolean useSynchronizationContecxt);
}

一个简单的例子:

CancellationTokenSource cts = new CancellationTokenSource();
ThreadPool.QueueUserWorkItem(o => LongTimeCalculate(cts.Token, 20));
Console.WriteLine("Press <ENTER> to cancel the calculate.");
Console.ReadKey();
cts.Cancel();

Press <ENTER> to cancel the calculate.
Calculate is cancelled!
Done!

假如你不想让这个calculate方法被取消,可以使用CancellationToken类中的静态None属性。

如果,你想通过一个CancellationTokenSource 协作式取消一个或多个方法,可以使用CancellationToken`s Register方法。关于这个方法,你可以传入一个Action<Object>的委托,一个state值,一个布尔值指定是否在调用该委托时使用同步执行上下文(SynchronizationContext)。

CancellationToken`s Register方法返回一个CancellationTokenRegistration:

public struct CancellationTokenRegistration : IEquatable<CancellationTokenRegistration>, IDisposable

{

public void Dispose();


}

因此,可以调用Dispose移除一个register方法。

下面简单的使用CancellationToken`s Register方法:

CancellationTokenSource cts = new CancellationTokenSource();
cts.Token.Register(() => Console.WriteLine("Method 1"));
cts.Token.Register(() => Console.WriteLine("Method 2"));
cts.Cancel();

输出:

Method 2
Method 1