您的位置:首页 > 编程语言 > C#

关于C#异步调用的知识点

2013-11-29 15:20 211 查看
1 异步的重要性

程序执行分为同步调用和异步调用的。同步调用,即线程1运行时,调用线程2,线程1等待线程2运行完成后,再运行线程1。

异步调用,即线程1运行时,调用线程2,线程1和线程2此时同时在运行,相当于并肩运行。

主程序运行的时候,势必存在一些小线程的操作,而如果不使用异步调用,主线程会等待小线程运行完之后再运行自己,即所谓的阻塞。如果小线程运行时间比较长,就会导致主线程不运作,反应在界面上出现卡住的现象。( 计算机中有些处理比较耗时。调用这种处理代码时,调用方如果站在那里苦苦等待,会严重影响程序性能。)

在单线程方式下,计算机是一台严格意义上的冯·诺依曼式机器,一段代码调用另一段代码时,只能采用同步调用,必须等待这段代码执行完返回结果后,调用方才能继续往下执行。有了多线程的支持,可以采用异步调用,调用方和被调方可以属于两个不同的线程,调用方启动被调方线程后,不等对方返回结果就继续执行后续代码。被调方执行完毕后,通过某种手段通知调用方:结果已经出来,请酌情处理。

所以,需要采用异步调用,使得小线程的运行不影响主线程的运行,即实现同时处理。

2 什么是异步调用

异步调用是一个可以无需等待被调用函数的返回值就让操作继续进行的方法。

异步的实现即多线程,一种简单的方式就是创建一个委托,然后异步调用它。 .Net Framework已经为我们提供了委托的异步调用方法。下面介绍三种使用委托实现异步的方法。

(1)投票(IsCompleted属性)

首先定义一个委托:

public delegate string MyDelegate(int ms);
Delegate类提供了BeginInvoke()方法,这个方法返回一个IAsyncResult接口,这个接口包含了该委托的相关信息,并且可以通过它的IsCompleted属性来判断该委托是否执行完成。下面是将要异步调用的方法:

static string DelegateMethod(int ms)
{
Console.WriteLine("TakesAWhile started");
Thread.Sleep(1000);
Console.WriteLine("TakesAWhile completed");
return "Hello world!";
}


下面是主线程的方法:

static void Imp1()
{
MyDelegate dl = DelegateMethod;

IAsyncResult ar = dl.BeginInvoke(5000, null, null);

while (!ar.IsCompleted)
{
Console.Write(".");
Thread.Sleep(50);
}
string result = dl.EndInvoke(ar);
Console.WriteLine("result: {0}", result);
}
可以看到,委托线程执行5秒钟,主线程不停的循环判断委托线程是否完成(用IsCompleted属性判断)。如果没完成则断续打点,如果完成则跳出循环。用EndInvoke方法获取委托的返回值。如果方法未执行完,EndInvoke方法就会一直阻塞,直到被调用的方法执行完毕。

(2)等待句柄(AsyncWaitHandle属性)

使用IAsyncResult的AsyncWaitHandle属性可以访问等待句柄,这个属性返回一个WaitHandle对象,这个对象的WaitOne()方法可输入一个超时时间作为参数,设置等待的最长时间。如果超时,WaitOne()方法返回一个bool值,true为等待成功(即委托完成),异步调用的方法与上面一样,下面是主线程实现:

static void Imp2()
{
MyDelegate dl = DelegateMethod;

IAsyncResult ar = dl.BeginInvoke(5000, null, null);
while (true)
{
Console.Write(".");
if (ar.AsyncWaitHandle.WaitOne(50))
{
Console.WriteLine("Can get the result now");
break;
}
}
string result = dl.EndInvoke(ar);
Console.WriteLine("result: {0}", result);
}
主线程每等待50秒做一次判断是否完成。

(3)异步回调(AsyncCallBack委托)

BeginInvoke方法第二个参数可传入一个AsnycCallBack委托类型的方法,当异步调用完成时会执行这个方法。我们可以用Lambda表达式来实现:

static void Imp3()
{
MyDelegate dl = DelegateMethod;
dl.BeginInvoke(5000, new AsyncCallback(ar =>
{
string result = dl.EndInvoke(ar);
Console.WriteLine("result: {0}", result);
}), null);
for (int i = 0; i < 100; i++)
{
Console.Write(".");
Thread.Sleep(50);
}
}
BeginInvoke方法的最后一个参数可以用IAsyncResult的AsyncState属性获取。

3 回调和调用
回调函数是一个程序员不能显式调用的函数;通过将回调函数的地址传给调用者从而实现调用。回调函数使用是必要的,在我们想通过一个统一接口实现不同的内容,这时用回掉函数非常合适。比如,我们为几个不同的设备分别写了不同的显示函数:

voidTVshow(); void ComputerShow(); void NoteBookShow()...等等。这是我们想用一个统一的显示函数,我们这时就可以用回掉函数了。void show(void (*ptr)()); 使用时根据所传入的参数不同而调用不同的回调函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: