【文章标题】: 乱涂C#多线程03
【文章作者】: 有酒醉
【作者邮箱】:
wuqr32@sina.com
【下载地址】: 自己搜索下载
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
二、异步委托
异步委托调用采用线程池线程执行异步操作,线程池通过为应用程序提供一个由系统管理的辅助线程池使我们可以更为有效地使用线程.CLR内置支持委托异步调用,所以我们完全可以异步地调用任何一个方法,只要将其封装在一个委托中.
示例 - 查看委托的内置结构
//
T.cs
//
Author by Yzl
public
delegate
int
AddDelegate(
int
first,
ref
int
second,
out
int
result);
编译为动态库:
D:/>csc /o+ /t:library T.cs
Microsoft (R) Visual C# .NET 编译器版本 7.10.6001.4
用于 Microsoft (R) .NET Framework 版本 1.1.4322
版权所有 (C) Microsoft Corporation 2001-2002。保留所有权利。
查看内置结构:
D:/>ildasm /TEXT T.dll
//
============== CLASS STRUCTURE DECLARATION ==================
.
class
public
auto ansi
sealed
AddDelegate extends [mscorlib]System.MulticastDelegate{}
//
=============== CLASS MEMBERS DECLARATION ===================
.
class
public
auto ansi
sealed
AddDelegate extends [mscorlib]System.MulticastDelegate{ .method
public
hidebysig specialname rtspecialname instance
void
.ctor(
object
'
object
'
,native
int
'
method
'
) runtime managed { } .method
public
hidebysig
virtual
instance int32 Invoke(int32 first,int32
&
second,[
out
] int32
&
result) runtime managed { } .method
public
hidebysig newslot
virtual
instance
class
[mscorlib]System.IAsyncResult BeginInvoke(int32 first,int32
&
second, [
out
] int32
&
result,
class
[mscorlib]System.AsyncCallback callback,
object
'
object
'
) runtime managed { } .method
public
hidebysig newslot
virtual
instance int32 EndInvoke(int32
&
second,[
out
] int32
&
result,
class
[mscorlib]System.IAsyncResult result) runtime managed { }}
//
end of class AddDelegate
//
*********** 反汇编完成 ***********************
我们可以看出BeginInvoke,EndInvoke都属于IL级别,并不定义在源代码级别.CLR自动生成它们进行异步调用.当然,我们也可以显式调用它们进行异步调用.
BeginInvoke -- 方法用于启动异步调用.它与需要异步执行的方法具有相同的参数,只不过还有两个额外的参数.BeginInvoke立即返回,不等待异步调用完成.返回值为IAsyncResult,用于监视调用进度.
EndInvoke -- 方法用于检索异步调用结果.如果异步调用未完成,EndInvoke 将一直阻塞到异步调用完成.注意!EndInvoke中的参数应包含ref,out
示例 - 显式异步调用
//
AsyncDemo.cs
//
Author by Yzl
using
System;
using
System.Text;
using
System.Reflection;
public
delegate
string
AddDelegate(
int
first,
ref
int
second,
out
int
result);
public
class
AsyncDemo
...
{ public static void Main(string[] args) ...{ int first = 2,second = 4,result; AddDelegate addDelegate = new AddDelegate(Add); // 同步调用 Console.WriteLine(addDelegate(first,ref second,out result)); // 显式异步调用 IAsyncResult ar = addDelegate.BeginInvoke(first,ref second,out result,null,null); try ...{ Console.WriteLine(" Async waiting:"+addDelegate.EndInvoke(ref second,out result,ar)); } catch(Exception ex) ...{ Console.WriteLine("Async exception occurred:"+ex.Message); } } private static string Add(int first,ref int second,out int result) ...{ result = first + second; StringBuilder sb = new StringBuilder(); sb.Append("In Add... "); sb.Append(first); sb.Append("+"); sb.Append(second); sb.Append("="); sb.Append(result); return sb.ToString(); } }
编译运行:
D:/>csc AsyncDemo.cs
D:/>AsyncDemo
In Add...
2+4=6
Async waiting:In Add...
2+4=6
PS:如果大家不知道该传哪些参数给BeginInvoke,EndInvoke,可以通过ildasm对委托进行反编译查看.
如果在异步操作中发生异常,那么系统将通过异常链传递给EndInvoke,这也是为什么将EndInvoke放到try语句中的原因.
示例 - 显式异步调用异常
//
AsyncDemo.cs
//
Author by Yzl
using
System;
using
System.Text;
using
System.Reflection;
public
delegate
string
AddDelegate(
int
first,
ref
int
second,
out
int
result);
public
class
AsyncDemo
...
{ public static void Main(string[] args) ...{ int first = 2,second = 4,result; AddDelegate addDelegate = new AddDelegate(Add); // 显式异步调用 IAsyncResult ar = addDelegate.BeginInvoke(first,ref second,out result,null,null); try ...{ Console.WriteLine(" Async waiting:"+addDelegate.EndInvoke(ref second,out result,ar)); } catch(Exception ex) ...{ Console.WriteLine("Async exception occurred: "+ex.Message); } } private static string Add(int first,ref int second,out int result) ...{ throw new Exception("Custom Async exception:9527"); } }
编译运行,异常最终在EndInvoke中被抛出;
D:/>csc AsyncDemo.cs
D:/>AsyncDemo
Async exception occurred:
Custom Async exception:9527
我们进行更深入的研究,查看下异步调用是否应用了线程池线程.将上面的程序改进一下:
//
AsyncDemo.cs
//
Author by Yzl
using
System;
using
System;
using
System.Text;
using
System.Threading;
using
System.Reflection;
public
delegate
string
AddDelegate(
int
first,
ref
int
second,
out
int
result);
public
class
AsyncDemo
...
{ public static void Main(string[] args) ...{ int result; AddSync(2,3,out result); AddSync(2,4,out result); AddSync(2,5,out result); AddAsync(2,7,out result); AddAsync(2,8,out result); AddAsync(2,9,out result); } // 同步调用 private static void AddSync(int first,int second,out int result) ...{ try ...{ Thread.Sleep(500); AddDelegate addDelegate = new AddDelegate(Add); Console.WriteLine(addDelegate(first,ref second,out result)); } catch(Exception ex) ...{ result = 0; Console.WriteLine(" Async exception occurred:"+ex.Message); } } // 异步调用 private static void AddAsync(int first,int second,out int result) ...{ AddDelegate addDelegate = new AddDelegate(Add); // 显式异步调用 IAsyncResult ar = addDelegate.BeginInvoke(first,ref second,out result,null,null); try ...{ Thread.Sleep(1000); Console.WriteLine(" Async waiting:"+addDelegate.EndInvoke(ref second,out result,ar)); } catch(Exception ex) ...{ Console.WriteLine(" Async exception occurred:"+ex.Message); } } private static string Add(int first,ref int second,out int result) ...{ if (second == 5 || second == 8) throw new Exception("second is 5 or 8!"); result = first + second; StringBuilder sb = new StringBuilder(); sb.Append("In Add... "); sb.Append("Current Thread Hash :"); sb.Append(Thread.CurrentThread.GetHashCode()); sb.Append(",ThreadPool:"); // 判断是否为线程池线程 sb.Append(Thread.CurrentThread.IsThreadPoolThread); sb.Append(" "); sb.Append(first); sb.Append("+"); sb.Append(second); sb.Append("="); sb.Append(result); return sb.ToString(); } }
运行结果:
In Add...
Current Thread Hash :1,ThreadPool:False
2+3=5
In Add...
Current Thread Hash :1,ThreadPool:False
2+4=6
Async exception occurred:second is 5 or 8!
Async waiting:In Add...
Current Thread Hash :3,ThreadPool:True
2+7=9
Async exception occurred:second is 5 or 8!
Async waiting:In Add...
Current Thread Hash :3,ThreadPool:True
2+9=11
很明显,在进行异步调用时应用到了线程池线程!同时我们可以发现线程池的某一线程(比如线程号:3)一旦被执行完,又会重新被利用起来!
示例 - 显式异步回调
//
AsyncCallBackDemo.cs
//
Author by Yzl
using
System;
using
System.Text;
using
System.Threading;
using
System.Reflection;
using
System.Runtime.Remoting.Messaging;
public
delegate
string
TempDelegate(
string
name);
public
class
AsyncCallBackDemo
...
{ public static void Main(string[] args) ...{ TempAsyncCallBack("Hello"); TempAsyncCallBack("Yzl"); TempAsyncCallBack("MT-6209"); Console.ReadLine();//去掉 } private static void TempAsyncCallBack(string name) ...{ TempDelegate tempDelegate = new TempDelegate(Temp); // 异步调用 IAsyncResult ar = tempDelegate.BeginInvoke(name,new AsyncCallback(CallbackMethod),null); } // 异步回调 private static void CallbackMethod(IAsyncResult ar) ...{ TempDelegate tempDelegate = ((AsyncResult)ar).AsyncDelegate as TempDelegate; try ...{ Console.WriteLine(" AsyncCallBack waiting:"+tempDelegate.EndInvoke(ar)); } catch(Exception ex) ...{ Console.WriteLine(" AsyncCallBack exception occurred:"+ex.Message); } } private static string Temp(string name) ...{ Thread.Sleep(1000); StringBuilder sb = new StringBuilder(); sb.Append("In Temp... "); sb.Append("Current Thread Hash :"); sb.Append(Thread.CurrentThread.GetHashCode()); sb.Append(",ThreadPool:"); // 判断是否为线程池线程 sb.Append(Thread.CurrentThread.IsThreadPoolThread); sb.Append(",Name="); sb.Append(name); return sb.ToString(); }}
运行结果:
AsyncCallBack waiting:In Temp...
Current Thread Hash :3,ThreadPool:True,Name=Hello
AsyncCallBack waiting:In Temp...
Current Thread Hash :4,ThreadPool:True,Name=Yzl
AsyncCallBack waiting:In Temp...
Current Thread Hash :5,ThreadPool:True,Name=MT-6209
可以看出,回调异步运行真正实现了异步,在程序顺序执行下来时,并不影响其线程池线程(线程号:3,4,5)的生成.如果你去掉下面语句:Console.ReadLine();的话,那么程序将什么也没输出便退出了.AsyncDemo.cs的情况则不同,main函数会等待一个个异步调用执行完毕再顺序执行.这样就造成了线程池线程(线程号3)可以不断地重新利用!
<续>
--------------------------------------------------------------------------------
【版权声明】: 本文原创于泉州软件基地, 转载请注明作者并保持文章的完整, 谢谢!
2007年02月08日 23:04:16