目錄
一、線程的定義
二、線程的基礎(chǔ)知識
三、以ThreadStart方式實現(xiàn)多線程
四、CLR線程池的工作者線程
五、CLR線程池的I/O線程
六、異步 SqlCommand
七、并行編程與PLINQ
八、計時器與鎖
五、CLR線程池的I/O線程
在前一節(jié)所介紹的線程都屬于CLR線程池的工作者線程,這一節(jié)開始為大家介紹一下CLR線程池的I/O線程
I/O 線程是.NET專為訪問外部資源所設(shè)置的一種線程,因為訪問外部資源常常要受到外界因素的影響,為了防止讓主線程受影響而長期處于阻塞狀態(tài),.NET為多 個I/O操作都建立起了異步方法,例如:FileStream、TCP/IP、WebRequest、WebService等等,而且每個異步方法的使用 方式都非常類似,都是以BeginXXX為開始,以EndXXX結(jié)束,下面為大家一一解說。
5.1 異步讀寫 FileStream
需要在 FileStream 異步調(diào)用 I/O線程,必須使用以下構(gòu)造函數(shù)建立 FileStream 對象,并把useAsync設(shè)置為 true。
FileStream stream = new FileStream ( string path, FileMode mode, FileAccess access, FileShare share, int bufferSize,bool useAsync ) ;
其中 path 是文件的相對路徑或絕對路徑; mode 確定如何打開或創(chuàng)建文件; access 確定訪問文件的方式; share 確定文件如何進程共享; bufferSize 是代表緩沖區(qū)大小,一般默認最小值為8,在啟動異步讀取或?qū)懭霑r,文件大小一般大于緩沖大小; userAsync代表是否啟動異步I/O線程。
注意:當(dāng)使用 BeginRead 和 BeginWrite 方法在執(zhí)行大量讀或?qū)憰r效果更好,但對于少量的讀/寫,這些方法速度可能比同步讀取還要慢,因為進行線程間的切換需要大量時間。
5.1.1 異步寫入
FileStream中包含BeginWrite、EndWrite 方法可以啟動I/O線程進行異步寫入。
public override IAsyncResult BeginWrite ( byte[] array, int offset, int numBytes, AsyncCallback userCallback, Object stateObject )
public override void EndWrite (IAsyncResult asyncResult )
BeginWrite 返回值為IAsyncResult, 使用方式與委托的BeginInvoke方法相似,最好就是使用回調(diào)函數(shù),避免線程阻塞。在最后兩個參數(shù)中,參數(shù)AsyncCallback用于綁定回調(diào) 函數(shù); 參數(shù)Object用于傳遞外部數(shù)據(jù)。要注意一點:AsyncCallback所綁定的回調(diào)函數(shù)必須是帶單個 IAsyncResult 參數(shù)的無返回值方法。
在例子中,把FileStream作為外部數(shù)據(jù)傳遞到回調(diào)函數(shù)當(dāng)中,然后在回調(diào)函數(shù)中利用IAsyncResult.AsyncState獲取FileStream對象,最后通過FileStream.EndWrite(IAsyncResult)結(jié)束寫入。
class Program
{
static void Main(string[] args)
{
//把線程池的最大值設(shè)置為1000 ThreadPool.SetMaxThreads(1000, 1000);
ThreadPoolMessage("Start");
//新立文件File.sour FileStream stream = new FileStream("File.sour", FileMode.OpenOrCreate,
FileAccess.ReadWrite,FileShare.ReadWrite,1024,true);
byte[] bytes = new byte[16384];
string message = "An operating-system ThreadId has no fixed relationship........";
bytes = Encoding.Unicode.GetBytes(message);
//啟動異步寫入 stream.BeginWrite(bytes, 0, (int)bytes.Length,new AsyncCallback(Callback),stream);
stream.Flush();
Console.ReadKey();
}
static void Callback(IAsyncResult result)
{
//顯示線程池現(xiàn)狀 Thread.Sleep(200);
ThreadPoolMessage("AsyncCallback");
//結(jié)束異步寫入 FileStream stream = (FileStream)result.AsyncState;
stream.EndWrite(result);
stream.Close();
}
//顯示線程池現(xiàn)狀 static void ThreadPoolMessage(string data)
{
int a, b;
ThreadPool.GetAvailableThreads(out a, out b);
string message = string.Format("{0}\n CurrentThreadId is {1}\n "+
"WorkerThreads is:{2} CompletionPortThreads is :{3}",
data, Thread.CurrentThread.ManagedThreadId, a.ToString(), b.ToString());
Console.WriteLine(message);
}
}
由輸出結(jié)果可以看到,在使用FileStream.BeginWrite方法后,系統(tǒng)將自動啟動CLR線程池中I/O線程。
5.1.2 異步讀取
FileStream 中包含 BeginRead 與 EndRead 可以異步調(diào)用I/O線程進行讀取。
public override IAsyncResult BeginRead ( byte[] array,int offset,int numBytes, AsyncCallback userCallback,Object stateObject)
public override int EndRead(IAsyncResult asyncResult)
其使用方式與BeginWrite和EndWrite相似,AsyncCallback用于綁定回調(diào)函數(shù); Object用于傳遞外部數(shù)據(jù)。在回調(diào)函數(shù)只需要使用IAsyncResut.AsyncState就可獲取外部數(shù)據(jù)。EndWrite 方法會返回從流讀取到的字節(jié)數(shù)量。
首先定義 FileData 類,里面包含F(xiàn)ileStream對象,byte[] 數(shù)組和長度。然后把FileData對象作為外部數(shù)據(jù)傳到回調(diào)函數(shù),在回調(diào)函數(shù)中,把IAsyncResult.AsyncState強制轉(zhuǎn)換為 FileData,然后通過FileStream.EndRead(IAsyncResult)結(jié)束讀取。最后比較一下長度,若讀取到的長度與輸入的數(shù)據(jù) 長度不一至,則拋出異常。
1 class Program
2 {
3 public class FileData
4 {
5 public FileStream Stream;
6 public int Length;
7 public byte[] ByteData;
8 }
9
10 static void Main(string[] args)
11 {
12 //把線程池的最大值設(shè)置為1000 13 ThreadPool.SetMaxThreads(1000, 1000);
14 ThreadPoolMessage("Start");
15 ReadFile();
16
17 Console.ReadKey();
18 }
19
20 static void ReadFile()
21 {
22 byte[] byteData=new byte[80961024];
23 FileStream stream = new FileStream("File1.sour", FileMode.OpenOrCreate,
24 FileAccess.ReadWrite, FileShare.ReadWrite, 1024, true);
25
26 //把FileStream對象,byte[]對象,長度等有關(guān)數(shù)據(jù)綁定到FileData對象中,以附帶屬性方式送到回調(diào)函數(shù) 27 FileData fileData = new FileData();
28 fileData.Stream = stream;
29 fileData.Length = (int)stream.Length;
30 fileData.ByteData = byteData;
31
32 //啟動異步讀取 33 stream.BeginRead(byteData, 0, fileData.Length, new AsyncCallback(Completed), fileData);
34 }
35
36 static void Completed(IAsyncResult result)
37 {
38 ThreadPoolMessage("Completed");
39
40 //把AsyncResult.AsyncState轉(zhuǎn)換為FileData對象,以FileStream.EndRead完成異步讀取 41 FileData fileData = (FileData)result.AsyncState;
42 int length=fileData.Stream.EndRead(result);
43 fileData.Stream.Close();
44
45 //如果讀取到的長度與輸入長度不一致,則拋出異常 46 if (length != fileData.Length)
47 throw new Exception("Stream is not complete!");
48
49 string data=Encoding.ASCII.GetString(fileData.ByteData, 0, fileData.Length);
50 Console.WriteLine(data.Substring(2,22));
51 }
52
53 //顯示線程池現(xiàn)狀 54 static void ThreadPoolMessage(string data)
55 {
56 int a, b;
57 ThreadPool.GetAvailableThreads(out a, out b);
58 string message = string.Format("{0}\n CurrentThreadId is {1}\n "+
59 "WorkerThreads is:{2} CompletionPortThreads is :{3}",
60 data, Thread.CurrentThread.ManagedThreadId, a.ToString(), b.ToString());
61 Console.WriteLine(message);
62 }
63
64 }
由輸出結(jié)果可以看到,在使用FileStream.BeginRead方法后,系統(tǒng)將自動啟動CLR線程池中I/O線程。
注意:如果你看到的測試結(jié)果正好相反:工作者線程為999,I/O線程為1000,這是因為FileStream的文件容量小于緩沖值1024所致的。此時文件將會一次性讀取或?qū)懭耄到y(tǒng)將啟動工作者線程而非I/O線程來處理回調(diào)函數(shù)。
5.2 異步操作TCP/IP套接字
在介紹 TCP/IP 套接字前先簡單介紹一下 NetworkStream 類,它是用于網(wǎng)絡(luò)訪問的基礎(chǔ)數(shù)據(jù)流。 NetworkStream 提供了好幾個方法控制套接字數(shù)據(jù)的發(fā)送與接收, 其中BeginRead、EndRead、BeginWrite、EndWrite 能夠?qū)崿F(xiàn)異步操作,而且異步線程是來自于CLR線程池的I/O線程。
public override int ReadByte ()
public override int Read (byte[] buffer,int offset, int size)
public override void WriteByte (byte value)
public override void Write (byte[] buffer,int offset, int size)
public override IAsyncResult BeginRead (byte [] buffer, int offset, int size, AsyncCallback callback, Object state )
public override int EndRead(IAsyncResult result)
public override IAsyncResult BeginWrite (byte [] buffer, int offset, int size, AsyncCallback callback, Object state )
public override void EndWrite(IAsyncResult result)
若要創(chuàng)建 NetworkStream,必須提供已連接的 Socket。而在.NET中使用TCP/IP套接字不需要直接與Socket打交道,因為.NET把Socket的大部分操作都放在 System.Net.TcpListener和System.Net.Sockets.TcpClient里面,這兩個類大大地簡化了Socket的操 作。一般套接字對象Socket包含一個Accept()方法,此方法能產(chǎn)生阻塞來等待客戶端的請求,而在TcpListener類里也包含了一個相似的 方法 public TcpClient AcceptTcpClient()用于等待客戶端的請求。此方法將會返回一個TcpClient 對象,通過 TcpClient 的 public NetworkStream GetStream()方法就能獲取NetworkStream對象,控制套接字數(shù)據(jù)的發(fā)送與接收。
下面以一個例子說明異步調(diào)用TCP/IP套接字收發(fā)數(shù)據(jù)的過程。
首先在服務(wù)器端建立默認地址127.0.0.1用于收發(fā)信息,使用此地址與端口500新建TcpListener對象,調(diào)用TcpListener.Start 偵聽傳入的連接請求,再使用一個死循環(huán)來監(jiān)聽信息。
在ChatClient類包括有接收信息與發(fā)送信息兩個功能:當(dāng)接收到客戶端請求時,它會利 用 NetworkStream.BeginRead 讀取客戶端信息,并在回調(diào)函數(shù)ReceiveAsyncCallback中輸出信息內(nèi)容,若接收到的信息的大小小于1時,它將會拋出一個異常。當(dāng)信息成功 接收后,再使用 NetworkStream.BeginWrite 方法回饋信息到客戶端
class Program
{
static void Main(string[] args)
{
//設(shè)置CLR線程池最大線程數(shù) ThreadPool.SetMaxThreads(1000, 1000);
//默認地址為127.0.0.1 IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
TcpListener tcpListener = new TcpListener(ipAddress, 500);
tcpListener.Start();
//以一個死循環(huán)來實現(xiàn)監(jiān)聽 while (true)
{ //調(diào)用一個ChatClient對象來實現(xiàn)監(jiān)聽 ChatClient chatClient = new ChatClient(tcpListener.AcceptTcpClient());
}
}
}
public class ChatClient
{
static TcpClient tcpClient;
static byte[] byteMessage;
static string clientEndPoint;
public ChatClient(TcpClient tcpClient1)
{
tcpClient = tcpClient1;
byteMessage = new byte[tcpClient.ReceiveBufferSize];
//顯示客戶端信息 clientEndPoint = tcpClient.Client.RemoteEndPoint.ToString();
Console.WriteLine("Client's endpoint is " + clientEndPoint);
//使用NetworkStream.BeginRead異步讀取信息 NetworkStream networkStream = tcpClient.GetStream();
networkStream.BeginRead(byteMessage, 0, tcpClient.ReceiveBufferSize,
new AsyncCallback(ReceiveAsyncCallback), null);
}
public void ReceiveAsyncCallback(IAsyncResult iAsyncResult)
{
//顯示CLR線程池狀態(tài) Thread.Sleep(100);
ThreadPoolMessage("\nMessage is receiving");
//使用NetworkStream.EndRead結(jié)束異步讀取 NetworkStream networkStreamRead = tcpClient.GetStream();
int length=networkStreamRead.EndRead(iAsyncResult);
//如果接收到的數(shù)據(jù)長度少于1則拋出異常 if (length < 1)
{
tcpClient.GetStream().Close();
throw new Exception("Disconnection!");
}
//顯示接收信息 string message = Encoding.UTF8.GetString(byteMessage, 0, length);
Console.WriteLine("Message:" + message);
//使用NetworkStream.BeginWrite異步發(fā)送信息 byte[] sendMessage = Encoding.UTF8.GetBytes("Message is received!");
NetworkStream networkStreamWrite=tcpClient.GetStream();
networkStreamWrite.BeginWrite(sendMessage, 0, sendMessage.Length,
new AsyncCallback(SendAsyncCallback), null);
}
//把信息轉(zhuǎn)換成二進制數(shù)據(jù),然后發(fā)送到客戶端 public void SendAsyncCallback(IAsyncResult iAsyncResult)
{
//顯示CLR線程池狀態(tài) Thread.Sleep(100);
ThreadPoolMessage("\nMessage is sending");
//使用NetworkStream.EndWrite結(jié)束異步發(fā)送 tcpClient.GetStream().EndWrite(iAsyncResult);
//重新監(jiān)聽 tcpClient.GetStream().BeginRead(byteMessage, 0, tcpClient.ReceiveBufferSize,
new AsyncCallback(ReceiveAsyncCallback), null);
}
//顯示線程池現(xiàn)狀 static void ThreadPoolMessage(string data)
{
int a, b;
ThreadPool.GetAvailableThreads(out a, out b);
string message = string.Format("{0}\n CurrentThreadId is {1}\n " +
"WorkerThreads is:{2} CompletionPortThreads is :{3}\n",
data, Thread.CurrentThread.ManagedThreadId, a.ToString(), b.ToString());
Console.WriteLine(message);
}
}
而在客戶端只是使用簡單的開發(fā)方式,利用TcpClient連接到服務(wù)器端,然后調(diào)用NetworkStream.Write方法發(fā)送信息,最后調(diào)用NetworkStream.Read方法讀取回饋信息
1 static void Main(string[] args)
2 {
3 //連接服務(wù)端 4 TcpClient tcpClient = new TcpClient("127.0.0.1", 500);
5
6 //發(fā)送信息 7 NetworkStream networkStream = tcpClient.GetStream();
8 byte[] sendMessage = Encoding.UTF8.GetBytes("Client request connection!");
9 networkStream.Write(sendMessage, 0, sendMessage.Length);
10 networkStream.Flush();
11
12 //接收信息 13 byte[] receiveMessage=new byte[1024];
14 int count=networkStream.Read(receiveMessage, 0,1024);
15 Console.WriteLine(Encoding.UTF8.GetString(receiveMessage));
16 Console.ReadKey();
17 }
注意觀察運行結(jié)果,服務(wù)器端的異步操作線程都是來自于CLR線程池的I/O線程
5.3 異步WebRequest
System.Net.WebRequest 是 .NET 為實現(xiàn)訪問 Internet 的 “請求/響應(yīng)模型” 而開發(fā)的一個 abstract 基類, 它 主要有三個子類:FtpWebRequest、HttpWebRequest、FileWebRequest。當(dāng)使用 WebRequest.Create(string uri)創(chuàng)建對象時,應(yīng)用程序就可以根據(jù)請求協(xié)議判斷實現(xiàn)類來進行操作。FileWebRequest、FtpWebRequest、 HttpWebRequest 各有其作用:FileWebRequest 使用 “file://路徑” 的URI方式實現(xiàn)對本地資源和內(nèi)部文件的請求/響應(yīng)、FtpWebRequest 使用FTP文件傳輸協(xié)議實現(xiàn)文件請求/響應(yīng)、HttpWebRequest 用于處理HTTP的頁面請求/響應(yīng)。由于使用方法相類似,下面就以常用的HttpWebRequest為例子介紹一下異步WebRequest的使用方法。
在使用ASP.NET開發(fā)網(wǎng)站的時候,往往會忽略了HttpWebRequest的使用,因為開發(fā) 都假設(shè)客戶端是使用瀏覽器等工具去閱讀頁面的。但如果你對REST開發(fā)方式有所了解,那對 HttpWebRequest 就應(yīng)該非常熟悉。它可以在路徑參數(shù)、頭文件、頁面主體、Cookie 等多處地方加入請求條件,然后對回復(fù)數(shù)據(jù)進行適當(dāng)處理。HttpWebRequest 包含有以下幾個常用方法用于處理請求/響應(yīng):
public override Stream GetRequestStream ()
public override WebResponse GetResponse ()
public override IAsyncResult BeginGetRequestStream ( AsyncCallback callback, Object state )
public override Stream EndGetRequestStream ( IAsyncResult asyncResult )
public override IAsyncResult BeginGetResponse ( AsyncCallback callback, Object state )
public override WebResponse EndGetResponse ( IAsyncResult asyncResult )
其中BeginGetRequestStream、EndGetRequestStream 用于異步向HttpWebRequest對象寫入請求信息; BeginGetResponse、EndGetResponse 用于異步發(fā)送頁面請求并獲取返回信息。使用異步方式操作Internet的“請求/響應(yīng)”,避免主線程長期處于等待狀態(tài),而操作期間異步線程是來自CLR 線程池的I/O線程。
注意:請求與響應(yīng)不能使用同步與異步混合開發(fā)模式,即當(dāng)請求寫入使用GetRequestStream同步模式,即使響應(yīng)使用BeginGetResponse異步方法,操作也與GetRequestStream方法在于同一線程內(nèi)。
下面以簡單的例子介紹一下異步請求的用法。
首先為Person類加上可序列化特性,在服務(wù)器端建立Hanlder.ashx,通過Request.InputStream 獲取到請求數(shù)據(jù)并把數(shù)據(jù)轉(zhuǎn)化為String對象,此實例中數(shù)據(jù)是以 “Id:1” 的形式實現(xiàn)傳送的。然后根據(jù)Id查找對應(yīng)的Person對象,并把Person對象寫入Response.OutStream 中返還到客戶端。
在客戶端先把 HttpWebRequird.Method 設(shè)置為 "post",使用異步方式通過BeginGetRequireStream獲取請求數(shù)據(jù)流,然后寫入請求數(shù)據(jù) “Id:1”。再使用異步方法BeginGetResponse 獲取回復(fù)數(shù)據(jù),最后把數(shù)據(jù)反序列化為Person對象顯示出來。
注意:HttpWebRequire.Method默認為get,在寫入請求前必須把HttpWebRequire.Method設(shè)置為post,否則在使用BeginGetRequireStream 獲取請求數(shù)據(jù)流的時候,系統(tǒng)就會發(fā)出 “無法發(fā)送具有此謂詞類型的內(nèi)容正文" 的異常。
Model
namespace Model
{
[Serializable]
public class Person
{
public int ID
{
get;
set;
}
public string Name
{
get;
set;
}
public int Age
{
get;
set;
}
}
}
服務(wù)器端
1 public class Handler : IHttpHandler {
2
3 public void ProcessRequest(HttpContext context)
4 {
5 //把信息轉(zhuǎn)換為String,找出輸入條件Id 6 byte[] bytes=new byte[1024];
7 int length=context.Request.InputStream.Read(bytes,0,1024);
8 string condition = Encoding.Default.GetString(bytes);
9 int id = int.Parse(condition.Split(new string[] { ":" },
10 StringSplitOptions.RemoveEmptyEntries)[1]);
11
12 //根據(jù)Id查找對應(yīng)Person對象 13 var person = GetPersonList().Where(x => x.ID == id).First();
14
15 //所Person格式化為二進制數(shù)據(jù)寫入OutputStream 16 BinaryFormatter formatter = new BinaryFormatter();
17 formatter.Serialize(context.Response.OutputStream, person);
18 }
19
20 //模擬源數(shù)據(jù) 21 private IList<Person> GetPersonList()
22 {
23 var personList = new List<Person>();
24
25 var person1 = new Person();
26 person1.ID = 1;
27 person1.Name = "Leslie";
28 person1.Age = 30;
29 personList.Add(person1);
30 ...........
31 return personList;
32 }
33
34 public bool IsReusable
35 {
36 get { return true;}
37 }
38 }
客戶端
class Program
{
static void Main(string[] args)
{
ThreadPool.SetMaxThreads(1000, 1000);
Request();
Console.ReadKey();
}
static void Request()
{
ThreadPoolMessage("Start");
//使用WebRequest.Create方法建立HttpWebRequest對象 HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(
"http://localhost:5700/Handler.ashx");
webRequest.Method = "post";
//對寫入數(shù)據(jù)的RequestStream對象進行異步請求 IAsyncResult result=webRequest.BeginGetRequestStream(
new AsyncCallback(EndGetRequestStream),webRequest);
}
static void EndGetRequestStream(IAsyncResult result)
{
ThreadPoolMessage("RequestStream Complete");
//獲取RequestStream HttpWebRequest webRequest = (HttpWebRequest)result.AsyncState;
Stream stream=webRequest.EndGetRequestStream(result);
//寫入請求條件 byte[] condition = Encoding.Default.GetBytes("Id:1");
stream.Write(condition, 0, condition.Length);
//異步接收回傳信息 IAsyncResult responseResult = webRequest.BeginGetResponse(
new AsyncCallback(EndGetResponse), webRequest);
}
static void EndGetResponse(IAsyncResult result)
{
//顯出線程池現(xiàn)狀 ThreadPoolMessage("GetResponse Complete");
//結(jié)束異步請求,獲取結(jié)果 HttpWebRequest webRequest = (HttpWebRequest)result.AsyncState;
WebResponse webResponse = webRequest.EndGetResponse(result);
//把輸出結(jié)果轉(zhuǎn)化為Person對象 Stream stream = webResponse.GetResponseStream();
BinaryFormatter formatter = new BinaryFormatter();
var person=(Person)formatter.Deserialize(stream);
Console.WriteLine(string.Format("Person Id:{0} Name:{1} Age:{2}",
person.ID, person.Name, person.Age));
}
//顯示線程池現(xiàn)狀 static void ThreadPoolMessage(string data)
{
int a, b;
ThreadPool.GetAvailableThreads(out a, out b);
string message = string.Format("{0}\n CurrentThreadId is {1}\n " +
"WorkerThreads is:{2} CompletionPortThreads is :{3}\n",
data, Thread.CurrentThread.ManagedThreadId, a.ToString(), b.ToString());
Console.WriteLine(message);
}
}
從運行結(jié)果可以看到,BeginGetRequireStream、BeginGetResponse方法是使用CLR線程池的I/O線程。
5.4 異步調(diào)用WebService
相比TCP/IP套接字,在使用WebService的時候,服務(wù)器端需要更復(fù)雜的操作處理,使用時間往往會更長。為了避免客戶端長期處于等待狀態(tài),在配置服務(wù)引用時選擇 “生成異步操作”,系統(tǒng)可以自動建立異步調(diào)用的方式。
以.NET 2.0以前,系統(tǒng)都是使用ASMX來設(shè)計WebService,而近年來WCF可說是火熱登場,下面就以WCF為例子簡單介紹一下異步調(diào)用WebService的例子。
由于系統(tǒng)可以自動生成異步方法,使用起來非常簡單,首先在服務(wù)器端建立服務(wù) ExampleService,里面包含方法Method?蛻舳艘么朔⻊(wù)時,選擇 “生成異步操作”。然后使用 BeginMethod 啟動異步方法, 在回調(diào)函數(shù)中調(diào)用EndMethod結(jié)束異步調(diào)用。
服務(wù)端
1 [ServiceContract]
2 public interface IExampleService
3 {
4 [OperationContract]
5 string Method(string name);
6 }
7
8 public class ExampleService : IExampleService
9 {
10 public string Method(string name)
11 {
12 return "Hello " + name;
13 }
14 }
15
16 class Program
17 {
18 static void Main(string[] args)
19 {
20 ServiceHost host = new ServiceHost(typeof(ExampleService));
21 host.Open();
22 Console.ReadKey();
23 host.Close();
24 }
25 }
26
27 <configuration>
28 <system.serviceModel>
29 <services>
30 <service name="Example.ExampleService">
31 <endpoint address="" binding="wsHttpBinding" contract="Example.IExampleService">
32 <identity>
33 <dns value="localhost" />
34 </identity>
35 </endpoint>
36 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
37 <host>
38 <baseAddresses>
39 <add baseAddress="http://localhost:7200/Example/ExampleService/" />
40 </baseAddresses>
41 </host>
42 </service>
43 </services>
44 </system.serviceModel>
45 </configuration>
客戶端
class Program
{
static void Main(string[] args)
{
//設(shè)置最大線程數(shù) ThreadPool.SetMaxThreads(1000, 1000);
ThreadPoolMessage("Start");
//建立服務(wù)對象,異步調(diào)用服務(wù)方法 ExampleServiceReference.ExampleServiceClient exampleService = new
ExampleServiceReference.ExampleServiceClient();
exampleService.BeginMethod("Leslie",new AsyncCallback(AsyncCallbackMethod),
exampleService);
Console.ReadKey();
}
static void AsyncCallbackMethod(IAsyncResult result)
{
Thread.Sleep(1000);
ThreadPoolMessage("Complete");
ExampleServiceReference.ExampleServiceClient example =
(ExampleServiceReference.ExampleServiceClient)result.AsyncState;
string data=example.EndMethod(result);
Console.WriteLine(data);
}
//顯示線程池現(xiàn)狀 static void ThreadPoolMessage(string data)
{
int a, b;
ThreadPool.GetAvailableThreads(out a, out b);
string message = string.Format("{0}\n CurrentThreadId is {1}\n " +
"WorkerThreads is:{2} CompletionPortThreads is :{3}\n",
data, Thread.CurrentThread.ManagedThreadId, a.ToString(), b.ToString());
Console.WriteLine(message);
}
}
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IExampleService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false"
hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288"
maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8"
useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Windows" negotiateServiceCredential="true"
algorithmSuite="Default" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:7200/Example/ExampleService/"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IExampleService"
contract="ExampleServiceReference.IExampleService"
name="WSHttpBinding_IExampleService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
注意觀察運行結(jié)果,異步調(diào)用服務(wù)時,回調(diào)函數(shù)都是運行于CLR線程池的I/O線程當(dāng)中。
億恩-天使(QQ:530997) 電話 037160135991 服務(wù)器租用,托管歡迎咨詢。
本文出自:億恩科技【mszdt.com】
服務(wù)器租用/服務(wù)器托管中國五強!虛擬主機域名注冊頂級提供商!15年品質(zhì)保障!--億恩科技[ENKJ.COM]
|