1.通过委托,开启异步线程
Action是委托类型,BeginInvoke 开启异步线程。正常情况下,Main线程是顺序执行的,但是开启异步线程后,程序的执行顺序由调度决定。执行结果可能先输出"Main",后输出"Method",也可能是相反顺序。
static void Method(string str)
{
Console.WriteLine(str);
}
static void Main(string[] args)
{
Action<string> action = Method;
//BeginInvoke 开启异步线程
action.BeginInvoke("Method", null, null);
Console.WriteLine("Main");
}
2.获得异步线程的返回值
想要获得异步线程的返回值,需要判断线程何时结束,判断异步线程结束的方法有:while循环,等待句柄,回调函数等。
2.1 while循环
BeginInvoke的返回值是IAsyncResult,表示当前线程的状态。IsCompleted表示当前线程是否结束。当线程结束后,调用EndInvoke 获得线程的返回值。
当函数执行时间比较长时,采用异步线程比较合适,比如下载,网络传输等。下面例子中计算整数的平方,不会花费太长时间,因此使用Thread.Sleep(10)使线程暂停10毫秒。
class Program
{
static int Square(int num)
{
Thread.Sleep(10);
return num * num;
}
static void Main(string[] args)
{
Func<int, int> func = Square;
IAsyncResult async = func.BeginInvoke(10, null, null); //IAsyncResult 表示当前线程的状态
while (!async.IsCompleted)
{
Console.Write(".");
}
//EndInvoke 获得异步线程的返回值
int result = func.EndInvoke(async);
Console.WriteLine("result = " + result);
Console.ReadKey();
}
}
执行结果
2.2 等待句柄
AsyncWaitHandle用于等待异步操作完成的WaitHandle,WaitOne阻止当前线程,直到WaitHandle收到信号,参数为设置的超时时间。如果该时间内线程结束,则返回ture,否则返回false。
class Program
{
static int Square(int num)
{
Thread.Sleep(10);
return num * num;
}
static void Main(string[] args)
{
Func<int, int> func = Square;
IAsyncResult async = func.BeginInvoke(10, null, null);
bool flag = async.AsyncWaitHandle.WaitOne(1000);
if (flag)
{
int result = func.EndInvoke(async);
Console.WriteLine("result = " + result);
}
Console.ReadKey();
}
}
2.3 回调函数
BeginInvoke倒数第二个参数是一个委托,当线程结束时,就调用该委托指向的回调方法。最后一个参数给回调方法传递数据。
OnCallBack是回调函数,线程结束时执行。func是传递给回调方法的参数。
class Program
{
static int Square(int num)
{
Thread.Sleep(10);
return num * num;
}
static void OnCallBack(IAsyncResult async)
{
Func<int, int> function = async.AsyncState as Func<int, int>;
int result = function.EndInvoke(async);
Console.WriteLine("在回调函数中取得结果:" + result);
}
static void Main(string[] args)
{
Func<int, int> func = Square;
func.BeginInvoke(10, OnCallBack, func);
Console.ReadKey();
}
}
2.4 Lambda表达式
Lambda表达式可以访问外部数据,所以func不再需要作为参数传递,BeginInvoke的最后一个参数设为null。
class Program
{
static int Square(int num)
{
Thread.Sleep(10);
return num * num;
}
static void Main(string[] args)
{
Func<int, int> func = Square;
func.BeginInvoke(10, async =>
{
int result = func.EndInvoke(async);
Console.WriteLine("在Lambda表达式取得结果:" + result);
}, null);
Console.ReadKey();
}
}