异步编程(进程,线程,计时器)

100 篇文章 0 订阅
39 篇文章 1 订阅

进程
 - 启动一个程序时,系统在内存中创建了一个新的进程(process).
 - 进程就是一组资源,他们构成了一个正在运行的程序。这些资源包括虚拟地址空间,文件句柄以及程序启动需要的其他东西载体。

 

线程
 - 在进程中,系统创建了一个叫做线程(thread)的内核对象,线程体现了一个程序的真实执行情况。
 - 程序开始运行时,系统在线程中开始执行Main方法的第一条语句。
 - 线程时由系统负责调度的处理器(不是进程)上的执行单位.

 

同步编程
 - 程序只有一个线程,从程序的第一行语句到最后一行语句顺序执行。

 

异步编程
 - 程序发起多个线程,理论上是同一时间执行。(实际上,不是完全真的在同一时间执行,处理器会按照时间片轮流执行)

多线程处理
 - 在程序中使用多个线程叫做多线程处理。增加了程序的负荷和额外的复杂度。
 - 为了帮我们降低创建和销毁线程相关的成本,CLR为每一个进程维护了一个线程池(thread pool). 一开始进程的线程时空的,如果进

程使用的线程被创建,并且完成了线程的执行,它不会被销毁,而是加入到进程的线程池中。之后,如果进程需要另外一个线程,CLR会

从池中还原一个线程,就节省了很多时间。
 - 多线程处理对GUI编程非常重要,保持良好的用户体验。

 

异步编程模式
 - C#有个简单易用的机制用于异步执行方法,那就是使用委托。
 - 如果委托对象在调用列表中只有一个方法,它就可以异步执行这个方法。
 - 委托类有两个方法,叫做BeginInvoke 和 EndInvoke
    * 使用方法如下:
   当调用委托的BeginInvoke方法是,它开始在线程中的独立线程上执行引用方法,并且立即返回原始线程。原始线程可以继续,而引用

方法会在线程池中并行执行。
   当程序希望获取已完成的异步方法的结果时,可以检查BeginInvoker返回的IAsyncResult的IsCompleted 属性,或调用委托的

EndInvoke方法来等待委托完成.


 - 异步方法调用的3种标准模式.
  (1)等待-直到完成(wait-until-done).
     -> 在发起了异步方法以及做了一些其他处理之后,原始线程就中断并且等异步方法完成之后再继续。
  (2)轮询(polling)
     -> 原始线程定期检查发起的线程是否完成,如果没有则可以继续做一些其他的事情.
  (3)回调(callback)
     -> 原始线程一直执行,无需等待或检查发起的线程是否完成。
     
BeginInvoke 和 EndInvoke 
 - BeginInvoke 从线程池中获取一个线程并且在新的线程开始时运行引用方法。
 - BeginInvoke 返回给调用线程一个实现IAsyncResult接口的对象,这个接口引用包含了异步方法的当前状态,原始线程然后可以继续

执行。


delegate long MyDel( int first, int second); //声明委托
...
static long Sum(int x, int y) { ...}         //定义方法来匹配委托。
...
MyDel del = new MyDel(Sum);        //创建委托对象.

//调用委托对象的BeginInvoke方法并且提供了参数3,5, callback(设null), state (设null) . 
IAsyncResult iar = del.BeginInvoke (3,5,null,null);

EndInvoke 方法用来获取由异步方法调用返回的值,并且释放线程使用的资源。

long result = del.EndInvoke(iar);

EndInvoke 提供了从异步方法调用的所有输出,包括ref 和out 参数. 如果委托的引用方法有ref 或out 参数, 他们必须包含在

EndInvoke 的参数列表中.

long result = del.EndInvoke(out someInt, iar);


等待-直到-结束(wait-untill-done)模式
- 原始线程发起一个异步方法的调用,做一些其他的处理,然后停止并等待,一直到线程结束。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Threading; 

//声明委托
delegate long MyDel(int first, int second);


namespace ConsoleApplication1
{
    class Program
    {
        static long Sum(int x, int y)  //声明方法匹配委托,用于异步执行。
        {
            Console.WriteLine(" Inside Sum");
            Thread.Sleep(3000);

            return (x + y); 

        }
        static void Main()
        {
            MyDel del = new MyDel(Sum);

            Console.WriteLine("Before BeginInvoke");
            IAsyncResult iar = del.BeginInvoke(3, 5, null, null); // 开始异步调用
            Console.WriteLine("After BreginInvoke");
            Console.WriteLine("Doing stuff");
            long result = del.EndInvoke(iar);  //等待结束并获取结果
            Console.WriteLine("After EndInvoke:{0}", result); 
        }
    }
}

 

输出:
Before BeginInvoke
After BeginInvoke
Doing stuff
 Inside Sum
After EndInvoke: 8      //等待3秒后,显示结果.


轮询(polling)模式
-原始线程发起了异步方法的调用,做一些其他事情,然后用IAsyncResult对象的IsComplete属性来定期检查开启的线程是否完成。如果

异步方法已经完成,原始线程就调用EndInvoke 并继续。否则,做一些其他的处理,然后再来定期检查。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Threading; 

//声明委托
delegate long MyDel(int first, int second);


namespace ConsoleApplication1
{
    class Program
    {
        static long Sum(int x, int y)  //声明方法匹配委托,用于异步执行。
        {
            Console.WriteLine(" Inside Sum");
            Thread.Sleep(5000);

            return (x + y); 

        }
        static void Main()
        {
            MyDel del = new MyDel(Sum);

            Console.WriteLine("Before BeginInvoke");
            IAsyncResult iar = del.BeginInvoke(3, 5, null, null); // 开始异步调用
            Console.WriteLine("After BreginInvoke");
            
            //检查异步方法是否完成
            while (!iar.IsCompleted)
            {
                Console.WriteLine("Not done, wait for 1 more second.");
                //处理一些其他事情
                Thread.Sleep(1000);
            }
            Console.WriteLine("Done");

            long result = del.EndInvoke(iar);  //等待结束并获取结果
            Console.WriteLine("After EndInvoke:{0}", result); 
        }
    }
}

输出:
Before BeginInvoke
After BeginInvoke
Not done, wait for 1 more second.
 Inside Sum
Not done, wait for 1 more second.
Not done, wait for 1 more second.
Not done, wait for 1 more second.
Not done, wait for 1 more second.
Done
After EndInvoke:8 

 

回调(callback)模式
-一旦初始线程发起了异步方法,就自己管自己,不再考虑同步。当异步方法调用结束后,系统调用一个用户自定义的方法来处理结果,

并且调用委托的EndInvoke 方法.
-BeginInvoke的参数列表中个最后的两个额外参数被回调方法用作:
 第一个参数,callback,是回调方法的名字.
 第二个参数,state,可以使null 或者传入回调方法的一个对象的引用。通过IAsyncResult参数的AsyncState属性来获取这个对象,参

数的类型是object.

回调方法
void asyncCallback(IAsyncResult iar)

IAsyncResult iar1=del.BeginInvoke(3,5,new AsyncCallback(CallWhenDone),null);
或 IAsyncResult iar1=del.BeginInvoke(3,5,CallWhenDone,null);

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Threading;
using System.Runtime.Remoting.Messaging; //调用AsyncResult类型.

//声明委托
delegate long MyDel(int first, int second);


namespace ConsoleApplication1
{
    class Program
    {
        static long Sum(int x, int y)  //声明方法匹配委托,用于异步执行。
        {
            Console.WriteLine(" Inside Sum");
            Thread.Sleep(500);    //备注A

            return (x + y); 

        }

        static void CallWhenDone(IAsyncResult iar)
        {
            Console.WriteLine("  Insdie CallWhenDone.");
            AsyncResult ar = (AsyncResult)iar;
            MyDel del = (MyDel)ar.AsyncDelegate;
            long result = del.EndInvoke(iar);
            Console.WriteLine("  The result is : {0}", result); 
        }

        static void Main()
        {
            MyDel del = new MyDel(Sum);

            Console.WriteLine("Before BeginInvoke");
            IAsyncResult iar = del.BeginInvoke(3, 5, new AsyncCallback(CallWhenDone), null); // 开始异步调用
            Console.WriteLine("Doing more work in main,ie. wait for 1 more second.");
            Thread.Sleep(1000);
            Console.WriteLine("Done with Main.");

        }
    }
}

输出:
Before BeginInvoke
Doing more work in main, ie. wait for 1 more second.
 Inside Sum
  Inside CallWhenDone.
  The result is : 8 
Done with Main.

备注A: 如果将此处修改为:  Thread.Sleep(5000);
则输出:
Before BeginInvoke
Doing more work in main, ie. wait for 1 more second.
 Inside Sum
Done with Main.

 

计时器
- 计时器在每次时间到期之后调用回调方法。回调放必须是TimerCallback委托形式的.
  void TimerCallback(object state)
- 当计时器到期后,系统会从线程池中的线程上开启一个回调方法,提供state对象作为其参数,并且开始运行.
- 可以设置的计时器的一些特性如下:
  dueTime:是回调方法首次被调用之前的时间。如果dueTime被设置为特殊的值Timeout Infinite ,则计时器不会开始。如果被设置为0,

回调函数会被立即调用.
  period 是两次成功调用回调函数之间的时间间隔。如果它的值设置为Timeout.Infinite,回调在首次被调用之后不会再被调用.
  state 可以使null 或在每次回调方法执行时要传入的对象的引用。

Timer类的最为常用的构造函数如下:
Timer(TimerCallback callback, object state, uint dueTime, uint period)

创建Timer对象的一个实例:
 //MyCallback是回调的名字,someObject是传给回调的对象, 2000毫秒后第一次调用,以后每隔1000毫秒调用一次.
Timer myTimer = new Timer( MyCallback, someObject, 2000, 1000 ) ;

Timer对象被创建后,我们还可以使用Change方法来改变 dueTime 或 period.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        int TimesCalled = 0;

        void Display(Object state)
        {
            Console.WriteLine("{0} {1}", (string)state, ++TimesCalled);
            
        }

        static void Main()
        {
            Program p = new Program();
            Timer myTimer = new Timer(p.Display, "Processing timer event", 2000, 1000);
            Console.WriteLine("Timer Start.");
            Console.ReadLine();
        }
    }
}

输出: 
Timer Start.
Processing timer event 1 
Processing timer event 2 
Processing timer event 3 
Processing timer event 4 
Processing timer event 5 
Processing timer event 6
... 
(每隔一秒会增加一行输出 ) 

.NET BCL 还提供了其他几个计时器类.

System.Windows.Forms.Timer -> 主要用于GUI编程.
- 这个类在Windows应用程序中使用,可以定期把WM_TIMER消息放到程序的消息队列中.
- 当程序从队列获取消息后,它会在主用户接口线程中异步处理。

System.Timers.Timer 
- 包含很多成员,可以通过属性和方法来操作计时器。
- 这个计时器可以运行在用户接口线程或工作者线程上。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值