源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

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

  • 时间:2022-02-24 17:41 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:使用异步方式调用同步方法(实例详解)
[b]说明:[/b] .NET Compact Framework 中不支持异步委托调用,也就是 BeginInvoke 和 EndInvoke 方法。 BeginInvoke 方法启动异步调用。该方法与您需要异步执行的方法具有相同的参数,还有另外两个可选参数。第一个参数是一个 AsyncCallback 委托,该委托引用在异步调用完成时要调用的方法。第二个参数是一个用户定义的对象,该对象将信息传入回调方法。BeginInvoke 会立即返回,而不等待异步调用完成。BeginInvoke 返回一个可用于监视异步调用进度的 IAsyncResult。 EndInvoke 方法检索异步调用的结果。在调用 BeginInvoke 之后随时可以调用该方法。如果异步调用尚未完成,则 EndInvoke 会一直阻止调用线程,直到异步调用完成。EndInvoke 的参数包括您需要异步执行的方法的 out 和 ref 参数(在 Visual Basic 中为 <Out> ByRef 和 ByRef)以及由 BeginInvoke 返回的 IAsyncResult。 [b]说明:[/b] 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。 [b]重要说明:[/b] 无论您使用何种方法,都要调用 EndInvoke 来完成异步调用。 [b]定义测试方法和异步委托[/b] 下面的代码示例演示异步调用同一个长时间运行的方法 TestMethod 的各种方式。TestMethod 方法会显示一条控制台消息,说明该方法已开始处理,休眠了几秒钟,然后结束。TestMethod 有一个 out 参数,该参数用于演示此种参数添加到 BeginInvoke 和 EndInvoke 的签名中的方式。您可以按同样的方式处理 ref 参数。 下面的代码示例演示 TestMethod 的定义和名为 AsyncMethodCaller 的、可用来异步调用 TestMethod 的委托。若要编译代码示例,必须包括 TestMethod 的定义和 AsyncMethodCaller 委托。 [b]C# [/b]
[u]复制代码[/u] 代码如下:
using System; using System.Threading; namespace AsyncTest {     public class AsyncDemo     {     [b]    //方法一 [/b]        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());         } [b]//方法二 [/b]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); }
[b]使用 EndInvoke 等待异步调用[/b] 异步执行方法的最简单方式是通过调用委托的 BeginInvoke 方法来开始执行方法,在主线程上执行一些操作,然后调用委托的 EndInvoke 方法。EndInvoke 可能会阻止调用线程,因为该方法直到异步调用完成后才返回。这种方式非常适合执行文件或网络操作。 [b]重要说明:[/b] 因为 EndInvoke 可能会阻塞,所以不应从服务于用户界面的线程调用该方法。 [b]C# [/b]
[u]复制代码[/u] 代码如下:
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);         }     } }
[b]使用 WaitHandle 等待异步调用[/b] 您可以使用由 BeginInvoke 返回的 IAsyncResult 的 AsyncWaitHandle 属性来获取 WaitHandle。异步调用完成时会发出 WaitHandle 信号,而您可以通过调用 WaitOne 方法等待它。 如果您使用 WaitHandle,则在异步调用完成之前或之后,但在通过调用 EndInvoke 检索结果之前,还可以执行其他处理。 [b]说明:[/b] 调用 EndInvoke 时不会自动关闭等待句柄。如果释放对等待句柄的所有引用,则当垃圾回收功能回收等待句柄时,将释放系统资源。若要在等待句柄使用完毕后立即释放系统资源,请调用 WaitHandle.Close 方法来释放等待句柄。显式释放可释放的对象时,垃圾回收的工作效率会更高。 [b]C# [/b]
[u]复制代码[/u] 代码如下:
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.". */ [b]轮询异步调用完成[/b] 您可以使用由 BeginInvoke 返回的 IAsyncResult 的 IsCompleted 属性来发现异步调用何时完成。从用户界面的服务线程中进行异步调用时可以执行此操作。轮询完成允许调用线程在异步调用在 ThreadPool 线程上执行时继续执行。 [b]C#C++VB [/b]
[u]复制代码[/u] 代码如下:
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.". */ [b]异步调用完成时执行回调方法[/b] 如果启动异步调用的线程不需要是处理结果的线程,则可以在调用完成时执行回调方法。回调方法在 ThreadPool 线程上执行。 若要使用回调方法,必须将表示回调方法的 AsyncCallback 委托传递给 BeginInvoke。也可以传递包含回调方法要使用的信息的对象。在回调方法中,可以将 IAsyncResult(回调方法的唯一参数)强制转换为 AsyncResult 对象。然后,可以使用 AsyncResult.AsyncDelegate 属性获取已用于启动调用的委托,以便可以调用 EndInvoke。 [b]有关示例的说明:[/b] TestMethod 的 threadId 参数为 out 参数(在 Visual Basic 中为 <Out> ByRef),因此 TestMethod 从不使用该参数的输入值。会将一个虚拟变量传递给 BeginInvoke 调用。如果 threadId 参数为 ref 参数(在 Visual Basic 中为 ByRef),则该变量必须为类级别字段,这样才能同时传递给 BeginInvoke 和 EndInvoke。 传递给 BeginInvoke 的状态信息是一个格式字符串,回调方法使用该字符串来设置输出消息的格式。因为作为类型 Object 进行传递,所以状态信息必须强制转换为正确的类型才能被使用。 回调是在 ThreadPool 线程上进行的。ThreadPool 线程是后台线程,这些线程不会在主线程结束后保持应用程序的运行,因此示例的主线程必须休眠足够长的时间以便回调完成。 [b]C# [/b]
[u]复制代码[/u] 代码如下:
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<string>((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);         }     }     } }
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部