当前位置:  编程技术>.net/c#/asp.net

使用异步方式调用同步方法(实例详解)

    来源: 互联网  发布时间:2014-10-24

    本文导语:  说明: .NET Compact Framework 中不支持异步委托调用,也就是 BeginInvoke 和 EndInvoke 方法。 BeginInvoke 方法启动异步调用。该方法与您需要异步执行的方法具有相同的参数,还有另外两个可选参数。第一个参数是一个 AsyncCallback 委托,...

说明:

.NET Compact Framework 中不支持异步委托调用,也就是 BeginInvoke 和 EndInvoke 方法。

BeginInvoke 方法启动异步调用。该方法与您需要异步执行的方法具有相同的参数,还有另外两个可选参数。第一个参数是一个 AsyncCallback 委托,该委托引用在异步调用完成时要调用的方法。第二个参数是一个用户定义的对象,该对象将信息传入回调方法。BeginInvoke 会立即返回,而不等待异步调用完成。BeginInvoke 返回一个可用于监视异步调用进度的 IAsyncResult。

EndInvoke 方法检索异步调用的结果。在调用 BeginInvoke 之后随时可以调用该方法。如果异步调用尚未完成,则 EndInvoke 会一直阻止调用线程,直到异步调用完成。EndInvoke 的参数包括您需要异步执行的方法的 out 和 ref 参数(在 Visual Basic 中为 ByRef 和 ByRef)以及由 BeginInvoke 返回的 IAsyncResult。

说明:

Visual Studio 2005 中的 IntelliSense 功能显示 BeginInvoke 和 EndInvoke 的参数。如果您没有使用 Visual Studio 或类似工具,或您使用的是带有 Visual Studio 2005 的 C#,请参见 异步编程概述 以获取为这些方法定义的参数的说明。

本主题中的代码示例演示了使用 BeginInvoke 和 EndInvoke 进行异步调用的四种常用方法。调用 BeginInvoke 之后,您可以执行下列操作:

进行某些操作,然后调用 EndInvoke 一直阻止到调用完成。

使用 IAsyncResult.AsyncWaitHandle 属性获取 WaitHandle,使用其 WaitOne 方法一直阻止执行直到发出 WaitHandle 信号,然后调用 EndInvoke。

轮询由 BeginInvoke 返回的 IAsyncResult,以确定异步调用何时完成,然后调用 EndInvoke。

将用于回调方法的委托传递给 BeginInvoke。异步调用完成后,将在 ThreadPool 线程上执行该方法。回调方法调用 EndInvoke。

重要说明:

无论您使用何种方法,都要调用 EndInvoke 来完成异步调用。

定义测试方法和异步委托

下面的代码示例演示异步调用同一个长时间运行的方法 TestMethod 的各种方式。TestMethod 方法会显示一条控制台消息,说明该方法已开始处理,休眠了几秒钟,然后结束。TestMethod 有一个 out 参数,该参数用于演示此种参数添加到 BeginInvoke 和 EndInvoke 的签名中的方式。您可以按同样的方式处理 ref 参数。

下面的代码示例演示 TestMethod 的定义和名为 AsyncMethodCaller 的、可用来异步调用 TestMethod 的委托。若要编译代码示例,必须包括 TestMethod 的定义和 AsyncMethodCaller 委托。

C#

代码如下:

using System;
using System.Threading;
namespace AsyncTest
{
    public class AsyncDemo
    {
        //方法一
        public string TestMethod(int callDuration, out int threadId)
        {
            Console.WriteLine("Test method begins.");
            Thread.Sleep(callDuration);
            threadId = Thread.CurrentThread.ManagedThreadId;
            return String.Format("My call time was {0}.", callDuration.ToString());
        }
//方法二
public float Addxy(float x, float y)
        {
            return x * y;
        }
    }
    //定义两个对应于方法的委托,参数同方法一致,委托的声明写在调用类里也是一样的,不限
    public delegate string AsyncMethodCaller(int callDuration, out int threadId);
    public delegate float AsyncMethodCaller2(float x, float y);
}

使用 EndInvoke 等待异步调用

异步执行方法的最简单方式是通过调用委托的 BeginInvoke 方法来开始执行方法,在主线程上执行一些操作,然后调用委托的 EndInvoke 方法。EndInvoke 可能会阻止调用线程,因为该方法直到异步调用完成后才返回。这种方式非常适合执行文件或网络操作。

重要说明:

因为 EndInvoke 可能会阻塞,所以不应从服务于用户界面的线程调用该方法。

C#

代码如下:

using System;
using System.Threading;
namespace AsyncTest
{
    public class AsyncMain
    {
        public static void Main()
        {
            // The asynchronous method puts the thread id here.
            int threadId;
            //实例化.
            AsyncDemo ad = new AsyncDemo();
            // 定义委托
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

            //通过委托调用方法,回调函数为null
            IAsyncResult result = caller.BeginInvoke(3000,
                out threadId, null, null);

            Thread.Sleep(0);
            Console.WriteLine("Main thread {0} does some work.",
                Thread.CurrentThread.ManagedThreadId);

            // Call EndInvoke to wait for the asynchronous call to complete,会阻塞
            // and to retrieve the results.
            string returnValue = caller.EndInvoke(out threadId, result);

            Console.WriteLine("The call executed on thread {0}, with return value "{1}".",
                threadId, returnValue);
        }
    }
}


使用 WaitHandle 等待异步调用

您可以使用由 BeginInvoke 返回的 IAsyncResult 的 AsyncWaitHandle 属性来获取 WaitHandle。异步调用完成时会发出 WaitHandle 信号,而您可以通过调用 WaitOne 方法等待它。

如果您使用 WaitHandle,则在异步调用完成之前或之后,但在通过调用 EndInvoke 检索结果之前,还可以执行其他处理。

说明:

调用 EndInvoke 时不会自动关闭等待句柄。如果释放对等待句柄的所有引用,则当垃圾回收功能回收等待句柄时,将释放系统资源。若要在等待句柄使用完毕后立即释放系统资源,请调用 WaitHandle.Close 方法来释放等待句柄。显式释放可释放的对象时,垃圾回收的工作效率会更高。

C#

代码如下:

using System;
using System.Threading;
namespace AsyncTest
{
    public class AsyncMain
    {
        static void Main()
        {
            // The asynchronous method puts the thread id here.
            int threadId;
            //实例化
            AsyncDemo ad = new AsyncDemo();

            //定义委托.
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

            //调用
            IAsyncResult result = caller.BeginInvoke(3000,
                out threadId, null, null);

            Thread.Sleep(0);
            Console.WriteLine("Main thread {0} does some work.",
                Thread.CurrentThread.ManagedThreadId);

            // Wait for the WaitHandle to become signaled.
            result.AsyncWaitHandle.WaitOne();

            // Perform additional processing here.
            // Call EndInvoke to retrieve the results.
            string returnValue = caller.EndInvoke(out threadId, result);

            // Close the wait handle.
            result.AsyncWaitHandle.Close();

            Console.WriteLine("The call executed on thread {0}, with return value "{1}".",
                threadId, returnValue);
        }
    }
}


/*输出如下:
Main thread 1 does some work.
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
*/

轮询异步调用完成

您可以使用由 BeginInvoke 返回的 IAsyncResult 的 IsCompleted 属性来发现异步调用何时完成。从用户界面的服务线程中进行异步调用时可以执行此操作。轮询完成允许调用线程在异步调用在 ThreadPool 线程上执行时继续执行。

C#C++VB

代码如下:

using System;
using System.Threading;
namespace AsyncTest
{
    public class AsyncMain
    {
        static void Main() {
            // The asynchronous method puts the thread id here.
            int threadId;

            //实例化.
            AsyncDemo ad = new AsyncDemo();

            //声明委托
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

            //调用.
            IAsyncResult result = caller.BeginInvoke(3000,
                out threadId, null, null);

            //轮询.
            while(result.IsCompleted == false) {
                Thread.Sleep(250);
                Console.Write(".");
            }
            //取结果.
            string returnValue = caller.EndInvoke(out threadId, result);

            Console.WriteLine("nThe call executed on thread {0}, with return value "{1}".",
                threadId, returnValue);
        }
    }
}


/* 输出:
Test method begins.
.............
The call executed on thread 3, with return value "My call time was 3000.".
*/

异步调用完成时执行回调方法

如果启动异步调用的线程不需要是处理结果的线程,则可以在调用完成时执行回调方法。回调方法在 ThreadPool 线程上执行。

若要使用回调方法,必须将表示回调方法的 AsyncCallback 委托传递给 BeginInvoke。也可以传递包含回调方法要使用的信息的对象。在回调方法中,可以将 IAsyncResult(回调方法的唯一参数)强制转换为 AsyncResult 对象。然后,可以使用 AsyncResult.AsyncDelegate 属性获取已用于启动调用的委托,以便可以调用 EndInvoke。

有关示例的说明:

TestMethod 的 threadId 参数为 out 参数(在 Visual Basic 中为 ByRef),因此 TestMethod 从不使用该参数的输入值。会将一个虚拟变量传递给 BeginInvoke 调用。如果 threadId 参数为 ref 参数(在 Visual Basic 中为 ByRef),则该变量必须为类级别字段,这样才能同时传递给 BeginInvoke 和 EndInvoke。

传递给 BeginInvoke 的状态信息是一个格式字符串,回调方法使用该字符串来设置输出消息的格式。因为作为类型 Object 进行传递,所以状态信息必须强制转换为正确的类型才能被使用。

回调是在 ThreadPool 线程上进行的。ThreadPool 线程是后台线程,这些线程不会在主线程结束后保持应用程序的运行,因此示例的主线程必须休眠足够长的时间以便回调完成。

C#

代码如下:

using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;
namespace AsyncTest
{
    public class AsyncMain
    {
        static void Main()
        {
            //实例化类.
            AsyncDemo ad = new AsyncDemo();

            //实例两个不同的委托,分别对应不同的方法.
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

AsyncMethodCaller2 caller2 = new AsyncMethodCaller2(ad.Addxy);

            // The threadId parameter of TestMethod is an out parameter, so
            // its input value is never used by TestMethod. Therefore, a dummy
            // variable can be passed to the BeginInvoke call. If the threadId
            // parameter were a ref parameter, it would have to be a class-
            // level field so that it could be passed to both BeginInvoke and
            // EndInvoke.
            int dummy = 0;

            // 调用时指定回调方法,在异步执行完后会自动调用该方法,用来取得执行的结果
            IAsyncResult result = caller.BeginInvoke(3000,
                out dummy,
                new AsyncCallback(CallbackMethod),
                "The call executed on thread {0}, with return value "{1}".");

caller2.BeginInvoke(2, 3, CallbackMethod2, "this is add");
            Console.WriteLine("The main thread {0} continues to execute...",
                Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(4000);

            Console.WriteLine("The main thread ends.");
        }

        // The callback method must have the same signature as the
        // AsyncCallback delegate.
        private void CallbackMethod(IAsyncResult ar)
        {
            // Retrieve the delegate.
            AsyncResult result = (AsyncResult) ar;
   //强制转换成对应的委托对象
            AsyncMethodCaller caller = (AsyncMethodCaller) result.AsyncDelegate;

            // Retrieve the format string that was passed as state
            // information.
            string formatString = (string) ar.AsyncState;

            // Define a variable to receive the value of the out parameter.
            // If the parameter were ref rather than out then it would have to
            // be a class-level field so it could also be passed to BeginInvoke.
            int threadId = 0;
            // Call EndInvoke to retrieve the results.
            string returnValue = caller.EndInvoke(out threadId, ar);


            // Use the format string to format the output message.
            Console.WriteLine(formatString, threadId, returnValue);
        }
private void CallbackMethod2(IAsyncResult ar)
        {
            // Retrieve the delegate.
            AsyncResult result = (AsyncResult)ar;
//强制转换成对应的委托对象
            AsyncMethodCaller2 caller = (AsyncMethodCaller2)result.AsyncDelegate;

            // 取得状态
            string formatString = (string)ar.AsyncState;
            //调用异步完成的方法,取得执行结果
            string returnValue = caller.EndInvoke(ar).ToString();

//此种方式是在windows应用程序给控件赋值时用,因为在非创建线程不能操作控件
            this.Invoke(new Action((u) => tb_datainfo.Text += u), returnValue);
            //tb_datainfo.Text = caller.EndInvoke(out threadId, ar);

            // Use the format string to format the output message.
            //Console.WriteLine(formatString, threadId, returnValue);
        }
    }
    }
}


    
 
 

您可能感兴趣的文章:

  • 使用BeginInvoke,EndInvoke异步调用委托的代码
  • 基于使用BeginInvoke,EndInvoke异步调用委托的实现代码
  • 使用jquery.upload.js实现异步上传示例代码
  • 跨平台python异步回调机制实现和使用方法
  • 解析使用enumerator模式简化异步操作的详解
  • .net4.5使用async和await异步编程实例
  • 使用jQuery异步加载 JavaScript脚本解决方案
  • python高并发异步服务器核心库forkcore使用方法
  • Android中BroadcastReceiver(异步接收广播Intent)的使用
  • 在Python中使用异步Socket编程性能测试
  • AMD异步模块定义介绍和Require.js中使用jQuery及jQuery插件的方法
  • 使用kendynet构建异步redis访问服务
  • php使用fscok实现异步调用
  • .NET中的async和await关键字使用及Task异步调用实例
  • asp.net 使用js分页实现异步加载数据
  • 在Python中使用SWIG调用C和C++程序
  • 新手:Linux下使用第三方C库(openssl),是调用.so文件还是直接调用.h文件?
  • Qt下使用Linux系统调用?
  • fork~exec不会使用,请问怎么使用,我只是想简单的用进程调用一个程序。
  • 关于使用Ptrace系统调用监控进程问题
  • 使用gdb时为什么调用list不出现代码
  • [求助]如何获取一个程序所使用的系统调用和参数?
  • linux不用命令方式读文件获取网络流量,如何使用C函数调用获取网络流量信息?
  • Unix下System函数实现中为何要使用shell去调用执行程序?
  • linux 内核编程中如何使用系统调用函数呢?
  • 请问驱动程序中系统调用使用情况
  • 如何使用ececv调用另外一个程序?
  • 关于使用vnc 远程调用的问题
  • 如何使用JAVA调用利用用VC写的已有的动态库
  • 请问在 linux 下如何使用 execl() 调用另一个多进程的程序?
  • php 使用system() 调用c程序的问题
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • linux下top命令详解包括top命令参数使用及结果(virt,res,shr)排序举例说明
  • 如何在Linux下使用脚本实现程序的自动重启!望各位详解!
  • linux top命令详解以及top命令的各项使用技巧详细说明
  • c# 空合并运算符“??”的使用详解
  • 在android开发中尽量不要使用中文路径的问题详解
  • 深入SQLServer中ISNULL与NULLIF的使用详解
  • MYSQL 批量替换之replace语法的使用详解
  • 汇编语言rep movsd 的使用详解
  • 使用SQL Server判断文件是否存在后再删除(详解)
  • 深入C#中使用SqlDbType.Xml类型参数的使用详解
  • 基于C语言fflush()函数的使用详解
  • 基于C++字符串替换函数的使用详解
  • Android开发笔记之:一分钟学会使用Logcat调试程序的详解
  • 深入分析Java内存区域的使用详解
  • Python Deque 模块使用详解
  • c语言中位字段与结构联合的组合使用详解
  • C#中is与As运算符号的使用详解
  • Web服务器/前端 iis7站长之家
  • 使用DateTime的ParseExact方法实现特殊日期时间的方法详解
  • 从汇编看c++的默认析构函数的使用详解
  • oracle合并列的函数wm_concat的使用详解
  • C++ I/O 成员 tellg():使用输入流读取流指针
  • 在测试memset函数的执行效率时,分为使用Cash和不使用Cash辆种方式,该如何控制是否使用缓存?
  • C++ I/O 成员 tellp():使用输出流读取流指针
  • 求ibm6000的中文使用手册 !从来没用过服务器,现在急需使用它,不知如何使用! 急!!!!!
  • Python不使用print而直接输出二进制字符串
  • 请问:在使用oracle数据库作开发时,是使用pro*c作开发好些,还是使用库函数如oci等好一些啊?或者它们有什么区别或者优缺点啊?
  • Office 2010 Module模式下使用VBA Addressof
  • 急求结果!!假设一个有两个元素的信号量集S,表示了一个磁带驱动器系统,其中进程1使用磁带机A,进程2同时使用磁带机A和B,进程3使用磁带机B。
  • windows下tinyxml.dll下载安装使用(c++解析XML库)
  • c#中SAPI使用总结——SpVoice的使用方法


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3