• C#3.0学习笔记(12)进程,线程和异步编程


      离职在家,没有什么事做,所以借这个机会总结一下关于异步编程的技术来跟各位园友分享。

    1,什么叫进程?什么叫线程?

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

      就创建了一个新的进程(Process)。

      线程:在进程中,系统创建了一个叫做线程(thread)的内核对象,线程体现了一个程序的真实执行情况。一旦程序准备完毕,系统在线程中开始执行Main方法的第一条语句。默

      认情况下,一个进程只包含一个线程,它从程序开始执行一直到程序结束。

    2,什么叫异步编程(或称为多线程)?

      在理解什么叫异步编程之前,我们先来看看什么叫同步编程,到目前为止,我们前面讲的所有程序都只有一个线程,并且从程序的第一行语句到最后一行语句顺序执行,这就叫同             

      步编程。异步编程指的是程序发起多个线程,它们在理论上是在同一时间执行的。(其实不一定真的在同一时间执行)  

    下面来介绍两种简单但非常强大的多线程技术,异步委托和计时器:

    异步委托:

    使用异步委托有三种标准模式:

    1,等待一直到完成(wait-until-done)模式:在发起了异步方法以及做了一些其它处理后,原始线程就中断并且等异步方法完成之后再继续。

    2,轮询(Polling)模式:原始线程定期检查发起的线程是否完成,如果没有则可以继续做一些其它的事情。

    3,回调(Callback)模式:原始线程一直执行,无需等待或检查发起的线程是否完成。在发起的线程中的引用方法完成之后,发起的线程就会调用回调方法,由回调方法在调用EndInvoke之前处理异步方法的

      结构。

    下面是这三种模式的执行过程图示:

     下面就看看这三种模式分别的完整示例:

    1,等待一直到结束模式的示例:

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

    namespace thread1
    {
    delegate long MyDel(int first,int second); //声明委托类型
    class Program
    {
    static long Sum(int x, int y) //声明异步方法,方法匹配委托。
    {
    Console.WriteLine(" Inside Sum");
    Thread.Sleep(100); //调用Thread类的Sleep方法将它自己挂起0.1秒。
    return x + y;
    }

    static void Main(string[] args)
    {
    MyDel del = new MyDel(Sum); //创建委托对象,并使用Sum方法来初始化它的调用列表

    Console.WriteLine("Before BeginInvoke");
    IAsyncResult iar = del.BeginInvoke(3, 5, null, null); //开始异步调用,BeginInvoke返回一个IAsyncResult接口的引用。
    Console.WriteLine("After BeginInvoke");

    Console.WriteLine("Doing stuff");

    long result = del.EndInvoke(iar); //等待结束并获取结果。必须把IAsyncResult对象的引用作为参数。
    Console.WriteLine("Ater EndInvoke:{0}",result);
    Console.ReadKey();
    }
    }
    }

    程序输出结果为:

    2,轮询(Polling)模式的示例:

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

    namespace thread2
    {
    delegate long MyDel(int first,int second); //声明委托类型。
    class Program
    {
    static void Main(string[] args)
    {
    MyDel del = new MyDel(Sum); //创建委托对象。

    IAsyncResult iar = del.BeginInvoke(3, 5, null, null); //发起异步调用,BeginInvoke返回一个IAsyncResult接口的引用。
    Console.WriteLine("After BeginInvoke");

    while (!iar.IsCompleted) //调用IAsyncResult接口的IsCompleted属性检查异步方法是否完成。
    {
    Console.WriteLine("Not Done");

    //继续处理。这里的“处理”仅仅是由0数到10000000。
    for (long i = 0; i < 10000000; i++)
    ; //空语句。
    }
    Console.WriteLine("Done");

    long result = del.EndInvoke(iar); //调用委托的EndInvoke方法来获取接口并进行清理。
    Console.WriteLine("Result:{0}",result);
    Console.ReadKey();

    }

    static long Sum(int x, int y) //声明方法匹配委托。
    {
    Console.WriteLine(" Inside Sum");
    Thread.Sleep(500); //调用Thread类的Sleep方法将它自己挂起0.5秒。
    return x + y;
    }
    }
    }

    程序输出结果为:

    3,回调(Callback)模式的示例代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Runtime.Remoting.Messaging;

    namespace thread3
    {
    delegate long MyDel(int first,int second); //声明委托类型。

    class Program
    {
    static long Sum(int x, int y) //声明方法匹配委托。
    {
    Console.WriteLine(" Inside Sum");
    Thread.Sleep(100); //调用Thread类的Sleep方法将它自己挂起0.1秒。
    return x + y;
    }

    static void CallWhenDone(IAsyncResult iar) //声明回调方法。
    {
    Console.WriteLine(" Inside CallWhenDone");
    AsyncResult ar = (AsyncResult)iar; //通过引用转换,将接口引用转换为AsyncResult类对象的引用。
    MyDel del = (MyDel)ar.AsyncDelegate; //调用类对象的AsyncDelegate属性并把它转化为委托类型,这样我们就可以调用委托的EndInvoke方法了。
    long result = del.EndInvoke(iar); //结束调用,获取异步方法调用的返回值,释放线程所用资源。
    Console.WriteLine(" The result is {0}",result);
    }

    static void Main(string[] args)
    {
    MyDel del = new MyDel(Sum); //创建委托对象。

    Console.WriteLine("Before BeginInvoke");
    IAsyncResult iar = del.BeginInvoke(3,5,CallWhenDone,null);

    Console.WriteLine("Doing more work in Main");
    Thread.Sleep(500);
    Console.WriteLine("Done with Main,Exiting");
    Console.ReadKey();
    }
    }
    }

    程序输出结果为:

    计时器:

    计时器提供了另外一种正规的重复运行异步方法的方法。尽管在.NET BCL中有好几个可用的Timer类,但在这里我只会介绍System.Threading命名空间中的一个。

    使用计时器需要注意的重要事项如下:

    1,计时器在每次时间到期后调用回调方法。回调方法必须是TimerCallback委托形式的。

    2,当计时器到期之后,系统会从线程池中的线程上开启一下回调方法,提供state对象作为其参数,并且开始运行。

    3,Timer类的构造函数接受回调方法名称,dueTime,period以及state作为参数,其最为常用的构造函数形式如下:

      Timer myTimer=new Timer(MyCallback,someObject,2000,1000);

      注:MyCallback为回调方法的名称。

        someObject为传给回调的对象。

        2000即dueTime表示2000毫秒后第一次调用。

        1000即period表示每1000毫秒调用一次。

    示例如下:

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

    namespace thread4
    {
    class Program
    {
    int TimesCalled = 0;

    protected void Display(object state)//声明回调方法。
    {
    Console.WriteLine("{0}{1}",(string)state,++TimesCalled);
    }

    static void Main(string[] args)
    {
    Program p = new Program();//创建类的实例。

    Timer myTimer = new Timer(p.Display,"Processing timer event",2000,1000);//创建Timer类对象。
    Console.WriteLine("Timer start");
    Console.ReadKey();
    }
    }
    }

    这段代码在被关闭前的5秒内产生了如下的输出:

      以上就是这次总结的关于多线程编程方面的知识,写了一下午了。正好今天是我的27岁的生日,我得去准备请同事吃饭了,在这里也希望自己在新的一年里身体健康,工作顺利。


  • 相关阅读:
    【Rust】变量绑定
    【Rust】枚举的使用
    1月25日 学习记录
    1月19日 学习记录
    1月22日 学习记录
    1月21日 学习记录
    1月29日 体温APP开发记录
    今日进度
    今日进度
    今日进度
  • 原文地址:https://www.cnblogs.com/mcgrady/p/2252793.html
Copyright © 2020-2023  润新知