当前位置: 移动技术网 > IT编程>开发语言>.net > .Net组件程序设计之异步调用

.Net组件程序设计之异步调用

2018年12月29日  | 移动技术网IT编程  | 我要评论

个人怎么交养老保险,韩成珠快播,国外黄色网站

.net程序设计之异步调用

 

说到异步调用,在脑海中首先想到就是begininvoke(),在一些常用对象中我们也会常常见到invoke()和begininvoke(), 要想让自己的组件可以被客户端调用或者是异步调用,这样的设计是合理的,这也是组件异步机制当中的一条 (说句题外话--其实大多数知识都隐藏在我们平时经常见到的对象或者是代码里,只不过是没有去细心的发现) 在.net中首先就会想到使用委托来进行异步调用,关于委托的定义在 委托与事件一文中已经大概的说过了,文中只是对委托进行了 大概的讲解,并没有对委托的使用来说明或者是例举一些示例。 在本篇中将会对委托进行一个基础的揭底,主要方向是异步调用。

 

一 委托的老调重弹

 

复制代码

 1     public class operation

 2     {

 3         public int addition(int num1, int num2)

 4         {

 5             return num1 + num2;

 6         }

 7         public int subtraction(int num1, int num2)

 8         {

 9             return num1 - num2;

10         }

11     }

复制代码

没有必要直接使用operation对象来进行加减运算,可以使用委托:

 

复制代码

1 public delegate int operationdelegate(int num1, int num2);

3 operation operation = new operation();

4 operationdelegate additiondelegate = operation.addition;

6 int result;

7 result = additiondelegate.invoke(3, 4);

8 debug.assert(result == 7);

复制代码

在使用委托进行调用的时候,当前线程是被阻塞的,只有当委托执行完毕了,才会把控制权交回到当前线程。

不过呢,委托可以用于进行异步调用目标方法的,委托只是一种特定的类型,编译器会把我们定义的各式各样的委托编译成

对应的类,好比operationdelegate委托一样,实则是被编译成这样的

 

复制代码

 1     public sealed class operationdelegate : multicastdelegate

 2     {

 3         public operationdelegate(object target, int methodptr) { }

 4         public virtual invoke(int num1,int num2)

 5         {

 6             ……

 7         }

 8 

 9         public virtual iasyncresult begininvoke(int num1,int num2,asynccallback 

10 

11 callback,object asyncstate)

12         {

13             ……

14         }

15 

16         public virtual int endinvoke(iasyncresult result)

17         {

18             ……

19         }

20     }

复制代码

这里只是回顾一下委托的定义。

 

二 异步调用模型

 

图1

 

 

 

在上图我们所见的有这几个模块, .net线程池、异步调用请求队列和一个应用程序的主线程。

假使现在从任务1开始执行到任务2、任务3,到了任务3的时候,任务3请求.net执行异步操作,如图2

 

图2

 

 

 

这个时候【任务3】已经被送入到了【异步请求队列】中,并且主线程是阻塞状态的,再看图3的执行过程:

 

图3

 

 

 

线程池会及时的发现【异步请求队列】中的任务,并且根据任务的信息,线程池会分配一个线程到任务所在的主线程中执行所请求的任务。 在异步任务执行时,这个时候主线程才会从阻塞中撤销,进入执行状态,上图中,就是开始执行任务4。

 

这里要说的就是,异步调用看起来是并行执行的,实际刚开始的时候还是顺序的,不过这时间在实际情况中是忽略不计的, 可以认为就是并行执行的吧。

 

 三 begininvoke()、endinvoke()

 

3.1 begininvoke()

 

begininvoke()函数定义如下:

 

1 public virtual iasyncresult begininvoke(int num1,int num2,asynccallback callback,object asyncstate)

2 {

3    ……

4 }

接受operationdelegate委托定义的原始签名的输入参数,还有两个额外参数,asynccallback是定义的委托, 用于异步调用完成时回调所用,这里不做讲解,后面会有讲到,还有一个是参数是一个状态对象,也可以认为是容器对象, 也会在后面的章节中讲到。

 

1 operation operation = new operation();

2 operationdelegate additiondelegate = operation.addition;

3 additiondelegate.begininvoke(3, 4, null, null);

3.2 iasyncresult接口

 

正如上面所看到的,begininvoke函数返回一个iasyncresult类型的值,那就来看一下iasyncresult的定义:

 

复制代码

1     public interface iasyncresult

2     {

3         object asyncstate { get; }

4         waithandle asyncwaithandle { get; }

5         bool completedsynchronously { get; }

6         bool iscompleted { get; }

7     }

复制代码

对于iasyncresult的详细用法 稍后会有讲解

 

看到第一节的invoke函数执行后,可以直接获取到返回值,怎么这个begininvoke函数执行了返回

 

iasyncresult类型,返回值在哪呢? 可以通过从begininvoke函数获得的iasyncresult交给endinvoke函数来获取返回值。

 

1 operation operation = new operation();

2 operationdelegate additiondelegate = operation.addition;

4 iasyncresult asyncresult = additiondelegate.begininvoke(3, 4, null, null);

5 int result = additiondelegate.endinvoke(asyncresult);

6 debug.assert(result == 7);

这里要说几点

 

第一.调用endinvoke函数的时候,当前线程是被阻塞的,它在等待begininvoke函数执行完毕。

 

第二.虽然委托可以管理多个目标方法,但是在异步调用中,所执行异步调用的委托,内部的管理列表只能有一个目标方法,不然会报 有异常。

 

第三.endinvoke()在每次异步调用操作时 只能调用一次。

 

第四.begininvoke()返回的iasyncresult类型的实例,只能传入它所调用begininvoke()委托的endinvoke()中,不然也会报有异常。

 

 

 

3.3 asyncresult

 

假使一个客户端在一个代码段或者是函数中使用begininvoke(),而在另一段或者是其他的函数中调用endinvoke(),这样客户端是不是就要保存iasyncresult对象,又或者一个客户端发起异步调用,并且由另一个 客户端来调用endinvoke(),这不仅仅要保存iasyncresult对象,还需要保存该委托对象,而且你还得传送过去。 还好.net是那么的机智,有system.runtime.remoting.messaging.asyncresult类型的存在。

 

复制代码

    public class asyncresult : iasyncresult, imessagesink

    {

 

        #region iasyncresult 成员

 

        public object asyncstate

        {

            get { throw new notimplementedexception(); }

        }

 

        public system.threading.waithandle asyncwaithandle

        {

            get { throw new notimplementedexception(); }

        }

 

        public bool completedsynchronously

        {

            get { throw new notimplementedexception(); }

        }

 

        public bool iscompleted

        {

            get { throw new notimplementedexception(); }

        }

 

        #endregion

 

        public bool endinvokecalled { get; set; }

 

        public virtual object asyncdelegate { get; }

 

 

        //imessagesink 成员

    }

复制代码

看着上面有个asyncdelegate的属性,会不会觉得很漂亮,不错,它就是原始发起委托的引用,看下如何使用asyncdelegate来使用endinvoke():

 

复制代码

 1     public class operationtest

 2     {

 3 

 4         public void test()

 5         {

 6             operation operation = new operation();

 7             operationdelegate additiondelegate = operation.addition;

 8             int result;

 9             result = getresult(additiondelegate.begininvoke(3, 4, null, null));

10         }

11 

12         private int getresult(iasyncresult asyncresult)

13         {

14             asyncresult asyncresult = (asyncresult)asyncresult;

15             operationdelegate operationdelegate = asyncresult.asyncdelegate as 

16 

17 operationdelegate;

18             if (operationdelegate != null)

19             {

20                 debug.assert(asyncresult.endinvokecalled == false);//endinvoke()是否被调用过

21                 return operationdelegate.endinvoke(asyncresult);

22             }

23             return -1;

24         }

25     }

复制代码

3.4 轮循或等待

 

看到这里,善于思考的朋友会发现,还存在着一个很大的问题,就是发起异步调用的客户端,如何知道自己 的异步函数是否执行完毕了?或者是想等待一会,做一些其他的处理,然后再继续等待,该怎么来实现呢?

 

从begininvoke()返回的iasyncresult接口有个asyncwaithandle属性,它是干吗的呢?就把它理解为消息接收器吧。

 

复制代码

1 operation operation = new operation();

2 operationdelegate additiondelegate = operation.addition;

3 iasyncresult asyncresult = additiondelegate.begininvoke(2, 3, null, null);

4 asyncresult.asyncwaithandle.waitone();//如果任务完成则不会阻塞 否则阻塞当前线程

5 int result;

6 result = additiondelegate.endinvoke(asyncresult);

7 debug.assert(result == 5);

复制代码

代码和3.2的几乎相同,区别就是这段代码保证了endinvoke()的调用者不会被阻塞。

 

看一下等待一下,如果没完成处理其他任务,回来再等待是怎么实现的。

 

复制代码

 1 operation operation = new operation();

 2 operationdelegate additiondelegate = operation.addition;

 3 iasyncresult asyncresult = additiondelegate.begininvoke(2, 3, null, null);

 4 while (asyncresult.iscompleted == false)//判断异步任务是否完成

 5 {

 6      asyncresult.asyncwaithandle.waitone(10,false);//如果任务完成则不会阻塞 否则阻塞当前线程10毫秒

 7     //这里做一些其他操作

 8 }

 9 int result;

10 result = additiondelegate.endinvoke(asyncresult);

11 debug.assert(result == 5);

复制代码

3.5 使用回调函数

 

现在我们要来说说begininvoke()的第三个参数了, public delegate void asynccallback(iasyncresult ar);

 

第三个参数就是系统提供的一个委托类型,委托签名也都看到了。 使用回调函数的好处就是不需要去处理等待操作了,因为在异步任务完成的时候, 会调用你传给begininvoke()里asynccallback委托所关联的目标方法。

 

复制代码

 1     public class operationtest

 2     {

 3 

 4         public void test()

 5         {

 6             operation operation = new operation();

 7             operationdelegate additiondelegate = operation.addition;

 8 

 9             additiondelegate.begininvoke(2, 3, new asynccallback(oncallback), null);

10         }

11 

12         private void oncallback(iasyncresult asyncresult)

13         {

14             asyncresult asyncresult = (asyncresult)asyncresult;

15             operationdelegate operationdelegate = asyncresult.asyncdelegate as 

16 

17 operationdelegate;

18             if (operationdelegate != null)

19             {

20                 debug.assert(asyncresult.endinvokecalled == false);

21                 int result=operationdelegate.endinvoke(asyncresult);

22                 console.writeline("operation returned" + result.tostring());

23             }

24         }

25     }

复制代码

这里需要说的是在异步任务完成时,执行的回调函数依然是在子线程当中,并不是在主线程中执行回调函数的。

 

题外话:最常见的就是在winform开发中,form中发起异步调用,然后回调函数操作form中的控件或者是

 

值的时候就会报错, 就是这个原因,因为它们不在一个线程也不在一个上下文中,基于.net安全策略这种操作是不允许的。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网