net中异步执行(一)

http://hi.baidu.com/maple0015/blog/item/7a11ed50f39a4f65853524ee.html


在写程序的过程中,我们可能会需要对某些功能实现异步操作,比如记录调用日志等。

提到异步,我们最容易想到的就是多线程:我们可以启动另外一个线程,把一部分工作交给另外一个线程去执行,而当前线程继续去做一些更加急迫的事情。这里的“把一部分工作交给另外一个线程取执行”,是通过将要执行的函数的函数入口地址告诉另外一个线程来实现的,当新的线程有了函数的入口地址,就可以调用该函数。

我们先来看一下怎样使用C#中的Thread类来实现异步。

  • 使用Thread类异步执行一个方法

在C#中,Thread类是常用的用来启动线程的类:

         static void Main( string [] args)
        
... {
             Thread thread
= new Thread(new ThreadStart(myStartingMethod));
             thread.Start();
         }


        
static void myStartingMethod()
        
... {
         }

实际上,这里创建的ThreadStart对象,封装的就是方法“myStartingMethod”的入口地址。C#中通过Delegate对象,可以方便的封装函数入口地址。

而Delegate,实际上是用来描述函数定义的,比如上面提到的ThreadStart委托,他的声明如下:

public delegate void ThreadStart();

这句话声明了一个叫做ThreadStart的委托类型,而且该声明表示:ThredStart这个委托类型,只能封装“返回值为void、没有参数”的函数的入口地址。如果我们给ThreadStart类的构造函数传递的方法不符合,则会出错:

         static void Main( string [] args)
        
... {
            
// 错误 “myStartingMethod”的重载均与委托“System.Threading.ThreadStart”不匹配
             Thread thread= new Thread(new ThreadStart(myStartingMethod));
             thread.Start();
         }


        
static void myStartingMethod( int a)
        
... {
         }

实际上,我们在使用多线程时,要异步执行的函数往往会有一些参数。比如记录日志时,我们需要告诉另外一个线程日志的信息。

  • 异步执行一个带参数的方法

    因此,Thread类除了接受ThreadStart委托,还接受另外一个带参数的委托类型ParameterizedThreadStart:

             static void Main( string [] args)
            
    ... {
                 Thread thread
    = new Thread(new ParameterizedThreadStart(myStartingMethod));
                 thread.Start(null);
             }


            
    static void myStartingMethod( object threadData)
            
    ... {
                
    // do something.
             }

    ParameterizedThreadStart 委托可以用来封装返回值为void、具有一个object类型参数的函数。这样,我们就可以往另外一个函数中传递参数了——只不过,如果要传递多个参数,我们必须将参数封装一下,弄到一个object对象中去。比如下面的例子中,本来我们需要传递两个整数的,但为了符合ParameterizedThreadStart的声明,我们需要改造一下函数:

             static void Main( string [] args)
            
    ... {
                 Thread thread
    = new Thread(new ParameterizedThreadStart(myStartingMethod));
                 MyStartingMethodParameterWarpper param
    = new MyStartingMethodParameterWarpper();
                 param.X
    = 1;
                 param.Y
    = 2;
                 thread.Start(param);
             }


            
    static void myStartingMethod( object threadData)
            
    ... {
                 MyStartingMethodParameterWarpper param
    = (MyStartingMethodParameterWarpper)threadData;
                
    int value= param.X + param.Y;
                
    // do something
             }


            
    public class MyStartingMethodParameterWarpper
            
    ... {
                
    publicint X;
                
    publicint Y;
             }

    ParameterizedThreadStart委托必须与Thread.Start(Object) 方法一起使用——委托只是用来传递函数入口,但函数的参数是通过Thread.Start方法传递的。

    另外需要注意的,从这里我们可以看到,这样的使用方法并不是类型安全的,我们无法保证myStartingMethod方法的参数threadData永远都是MyStartingMethodParameterWarpper 类型,因此我们还需要加上判断;另外这样实际上也加大了程序间的沟通成本:如果有人需要异步执行myStartingMethod方法,那么他就必须知道其参数的实际类型并保证参数传递正确,而这块编译器已经无法通过编译错误的方式通知你了。



    .

  • 你可能感兴趣的:(thread,多线程,object,String,C#,编译器)