IAsyncResult 异步设计模式通过名为 BeginOperationName 和 EndOperationName 的两个方法来实现原同步方法的异步调用,如 FileStream 类提供了 BeginRead 和 EndRead 方法来从文件异步读取字节,它们是 Read 方法的异步版本。
IAsyncResult接口:
public interface IAsyncResult
{
// 获取用户定义的对象,该对象限定或包含有关异步操作的信息。
object AsyncState { get; }
// 获取用于等待异步操作完成的WaitHandle。
WaitHandle AsyncWaitHandle { get; }
// 获取一个值,该值指示异步操作是否同步完成。
bool CompletedSynchronously { get; }
// 获取一个值,该值指示异步操作是否已完成。
bool IsCompleted { get; }
}
补充说明:WaitHandle用来封装等待对共享资源进行独占访问的操作系统特定的对象。它是一个抽象类,我们一般不直接用,而是用它的派生类:
- AutoResetEvent:表示线程同步事件在一个等待线程释放后收到信号时自动重置。 此类不能被继承。
- ManualResetEvent:表示线程同步事件,收到信号时,必须手动重置该事件。 此类不能被继承。
- EventWaitHandle:表示一个线程同步事件。结合了前2个。
使用示例
下面了解一些详细使用。
用委托(Delegate)的 BeginInvoke 和 EndInvoke 方法操作线程
BeginInvoke 方法可以使用线程异步地执行委托所指向的方法。然后通过 EndInvoke 方法获得方法的返回值(EndInvoke 方法的返回值就是被调用方法的返回值),或是确定方法已经被成功调用。
class Program
{
private delegate int NewTaskDelegate(int ms);
static void Main(string[] args)
{
NewTaskDelegate task = NewTask;
IAsyncResult asyncResult = task.BeginInvoke(2000, null, null);
// //EndInvoke方法将被阻塞2秒
int result = task.EndInvoke(asyncResult);
Console.WriteLine(result);
Console.Read();
}
private static int NewTask(int ms)
{
Console.WriteLine("任务开始");
Thread.Sleep(ms);
Random random = new Random();
int n = random.Next(10000);
Console.WriteLine("任务完成");
return n;
}
}
使用IAsyncResult.IsCompleted属性来判断异步调用是否完成
class Program
{
private delegate int NewTaskDelegate(int ms);
static void Main(string[] args)
{
NewTaskDelegate task = NewTask;
IAsyncResult asyncResult = task.BeginInvoke(2000, null, null);
// 等待异步执行完成
while (!asyncResult.IsCompleted)
{
Console.Write("*");
Thread.Sleep(100);
}
// 由于异步调用已经完成,因此, EndInvoke会立刻返回结果
int result = task.EndInvoke(asyncResult);
Console.WriteLine(result);
Console.Read();
}
private static int NewTask(int ms)
{
Console.WriteLine("任务开始");
Thread.Sleep(ms);
Random random = new Random();
int n = random.Next(10000);
Console.WriteLine("任务完成");
return n;
}
}
使用WaitOne方法等待异步方法执行完成
WaitOne的第一个参数表示要等待的毫秒数,在指定时间之内,WaitOne方法将一直等待,直到异步调用完成,并发出通知,WaitOne方法才返回true。当等待指定时间之后,异步调用仍未完成,WaitOne方法返回false,如果指定时间为0,表示不等待,如果为-1,表示永远等待,直到异步调用完成。
class Program
{
private delegate int NewTaskDelegate(int ms);
static void Main(string[] args)
{
NewTaskDelegate task = NewTask;
IAsyncResult asyncResult = task.BeginInvoke(2000, null, null);
// 等待异步执行完成
while (!asyncResult.AsyncWaitHandle.WaitOne(100, false))
{
Console.WriteLine("*");
}
// 由于异步调用已经完成,因此, EndInvoke会立刻返回结果
int result = task.EndInvoke(asyncResult);
Console.WriteLine(result);
Console.Read();
}
private static int NewTask(int ms)
{
Console.WriteLine("任务开始");
Thread.Sleep(ms);
Random random = new Random();
int n = random.Next(10000);
Console.WriteLine("任务完成");
return n;
}
}
使用回调方法获取返回值
class Program
{
private delegate int NewTaskDelegate(int ms);
static void Main(string[] args)
{
NewTaskDelegate task = NewTask;
IAsyncResult asyncResult = task.BeginInvoke(2000, MethodCompleted, task);
Console.Read();
}
private static int NewTask(int ms)
{
Console.WriteLine("任务开始");
Thread.Sleep(ms);
Random random = new Random();
int n = random.Next(10000);
Console.WriteLine("任务完成");
return n;
}
private static void MethodCompleted(IAsyncResult asyncResult)
{
if (asyncResult == null || asyncResult.AsyncState == null)
{
Console.WriteLine("回调失败!!!");
return;
}
int result = (asyncResult.AsyncState as NewTaskDelegate).EndInvoke(asyncResult);
Console.WriteLine("任务完成,结果:" + result);
}
}
重点需要注意BeginInvoke方法的参数传递方式:
前面是其委托本身的参数。 倒数第二个参数(MethodCompleted)是回调方法委托类型,他是回调方法的委托,此委托没有返回值,有一个IAsyncResult类型的参数,当method方法执行完后,系统会自动调用MethodCompleted方法。 最后一个参数(task)需要向MethodCompleted方法中传递一些值,一般可以传递被调用方法的委托,这个值可以使用IAsyncResult.AsyncState属性获得。
网友评论