异步多线程

通过轮询方式,使用IsCompleted属性判断异步操作是否完成,这样在异步操作未完成前就可以让主线程执行另外的工作。代码如下:


class Program
    {
        delegate string MyDelegate(string name);

        static void Main(string[] args)
        {
            ThreadMessage("Main Thread");

            //建立委托

            MyDelegate myDelegate = new MyDelegate(Hello);

            //异步调用委托,获取计算结果

            IAsyncResult result = myDelegate.BeginInvoke("Leslie", null, null);

            //在异步线程未完成前执行其他工作

            while (!result.IsCompleted)

            {
                Thread.Sleep(200);      //虚拟操作

                Console.WriteLine("Main thead do work!");
            }

            //下列 AsyncWaitHandle.WaitOne(int timeout) 可达到相同效果

            //while (!result.AsyncWaitHandle.WaitOne(200))

            //{

            //    Console.WriteLine("Main thead do work!");

            //}

 

            //此处可加入多个检测对象, while (!result.IsCompleted) ,while (!result2.IsCompleted)...也可以判断多个

            //WaitHandle[] waitHandleList = new WaitHandle[] { result.AsyncWaitHandle,........ };

            //WaitHandle[] waitHandleList = new WaitHandle[] { result.AsyncWaitHandle};

            //while (!WaitHandle.WaitAll(waitHandleList,200))

            //{

            //    Console.WriteLine("Main thead do work!");

            //}

string data = myDelegate.EndInvoke(result); Console.WriteLine(data); Console.ReadKey(); } static string Hello(string name) { ThreadMessage("Async Thread"); Thread.Sleep(2000); return "Hello " + name; } static void ThreadMessage(string data) { string message = string.Format("{0}\n ThreadId is:{1}", data, Thread.CurrentThread.ManagedThreadId); Console.WriteLine(message); } }

 


 

上诉情况好比,硬件中的 总线 被占用的情况,如果外设需要请求总线,那么需要不断的询问 是否别人使用完毕,或者我是否可以申请了。

这种方式,现实中比较贴切,但是对于追求高效率的硬件设备,过于频繁的请求可不是特别的好。使用轮询方式来检测异步方法的状态

非常麻烦,而且效率不高,有见及此,.NET为 IAsyncResult BeginInvoke(AsyncCallback , object)准备了一个回调函数。使用

AsyncCallback 就可以绑定一个方法作为回调函数,回调函数必须是带参数 IAsyncResult 且无返回值的方法:

void AsycnCallbackMethod(IAsyncResult result) 。在BeginInvoke方法完成后,系统就会调用AsyncCallback所绑定的回调函数

,最后回调函数中调用 XXX EndInvoke(IAsyncResult result) 就可以结束异步方法,它的返回值类型与委托的返回值一致。

 

如下代码:利用回调函数实现异步多线程调用,也是在现实中比较实用的


 

class Program
{
public class Person
{
public string Name;
public int Age;
}

delegate string MyDelegate(string name);

static void Main(string[] args)
{
ThreadMessage("主线程开始!");

//建立委托
MyDelegate myDelegate = new MyDelegate(Hello);

//建立Person对象
Person person = new Person();
person.Name = "Elva";
person.Age = 27;

//异步调用委托,输入参数对象person, 获取计算结果
myDelegate.BeginInvoke("Leslie", new AsyncCallback(Completed), person);

//在启动异步线程后,主线程可以继续工作而不需要等待
for (int n = 0; n < 6; n++)
{
Console.WriteLine(" 主线程运行!");
Thread.Sleep(2000); //为了看到异步线程结束后主线程还在工作,sleep

}
Console.WriteLine(" 主线程运行!");
Console.WriteLine("");
Console.ReadKey();
}

static string Hello(string name)
{
ThreadMessage("异步线程运行!");
Thread.Sleep(2000);
return "\nHello " + name;
}

static void Completed(IAsyncResult result) //可以用该返回返回
{
ThreadMessage("异步线程完成");

//获取委托对象,调用EndInvoke方法获取运行结果
AsyncResult _result = (AsyncResult)result;
MyDelegate myDelegate = (MyDelegate)_result.AsyncDelegate;
string data = myDelegate.EndInvoke(_result);
//获取Person对象
Person person = (Person)result.AsyncState;
string message = person.Name + "'s age is " + person.Age.ToString();
Console.WriteLine(data + "\n" + message);
}

static void ThreadMessage(string data)
{
string message = string.Format("{0}\n 当前线程ID为:{1}",
data, Thread.CurrentThread.ManagedThreadId);
Console.WriteLine(message);
}
}

主线在调用BeginInvoke方法可以继续执行其他命令,而无需再等待了,这无疑比使用轮询方式判断异步方法是否完成更有优势。
在异步方法执行完成后将会调用AsyncCallback所绑定的回调函数,注意一点,回调函数依然是在异步线程中执行,这样就不会影响主线程的运行,
这也使用回调函数最值得青昧的地方。
在回调函数中有一个既定的参数IAsyncResult,把IAsyncResult强制转换为AsyncResult后,就可以通过 AsyncResult.AsyncDelegate 获取原委托,
再使用EndInvoke方法获取计算结果。
posted @ 2016-03-24 20:11  艾野草  阅读(266)  评论(0编辑  收藏  举报