離職在家,沒有什麼事做,所以借這個機會總結一下關於異步編程的技術來跟各位園友分享。
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歲的生日,我得去准備請同事吃飯了,在這裡也希望自己在新的一年裡身體健康,工作順利。